/src/botan/src/lib/pubkey/pem/pem.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * PEM Encoding/Decoding |
3 | | * (C) 1999-2007 Jack Lloyd |
4 | | * |
5 | | * Botan is released under the Simplified BSD License (see license.txt) |
6 | | */ |
7 | | |
8 | | #include <botan/pem.h> |
9 | | #include <botan/data_src.h> |
10 | | #include <botan/base64.h> |
11 | | #include <botan/exceptn.h> |
12 | | |
13 | | namespace Botan::PEM_Code { |
14 | | |
15 | | namespace { |
16 | | |
17 | | std::string linewrap(size_t width, const std::string& in) |
18 | 0 | { |
19 | 0 | std::string out; |
20 | 0 | for(size_t i = 0; i != in.size(); ++i) |
21 | 0 | { |
22 | 0 | if(i > 0 && i % width == 0) |
23 | 0 | { |
24 | 0 | out.push_back('\n'); |
25 | 0 | } |
26 | 0 | out.push_back(in[i]); |
27 | 0 | } |
28 | 0 | if(!out.empty() && out[out.size()-1] != '\n') |
29 | 0 | { |
30 | 0 | out.push_back('\n'); |
31 | 0 | } |
32 | |
|
33 | 0 | return out; |
34 | 0 | } |
35 | | |
36 | | } |
37 | | |
38 | | /* |
39 | | * PEM encode BER/DER-encoded objects |
40 | | */ |
41 | | std::string encode(const uint8_t der[], size_t length, const std::string& label, size_t width) |
42 | 0 | { |
43 | 0 | const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; |
44 | 0 | const std::string PEM_TRAILER = "-----END " + label + "-----\n"; |
45 | |
|
46 | 0 | return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); |
47 | 0 | } |
48 | | |
49 | | /* |
50 | | * Decode PEM down to raw BER/DER |
51 | | */ |
52 | | secure_vector<uint8_t> decode_check_label(DataSource& source, |
53 | | const std::string& label_want) |
54 | 0 | { |
55 | 0 | std::string label_got; |
56 | 0 | secure_vector<uint8_t> ber = decode(source, label_got); |
57 | 0 | if(label_got != label_want) |
58 | 0 | throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + |
59 | 0 | ", got " + label_got); |
60 | 0 | return ber; |
61 | 0 | } |
62 | | |
63 | | /* |
64 | | * Decode PEM down to raw BER/DER |
65 | | */ |
66 | | secure_vector<uint8_t> decode(DataSource& source, std::string& label) |
67 | 0 | { |
68 | 0 | const size_t RANDOM_CHAR_LIMIT = 8; |
69 | |
|
70 | 0 | label.clear(); |
71 | |
|
72 | 0 | const std::string PEM_HEADER1 = "-----BEGIN "; |
73 | 0 | const std::string PEM_HEADER2 = "-----"; |
74 | 0 | size_t position = 0; |
75 | |
|
76 | 0 | while(position != PEM_HEADER1.length()) |
77 | 0 | { |
78 | 0 | uint8_t b; |
79 | 0 | if(!source.read_byte(b)) |
80 | 0 | throw Decoding_Error("PEM: No PEM header found"); |
81 | 0 | if(static_cast<char>(b) == PEM_HEADER1[position]) |
82 | 0 | ++position; |
83 | 0 | else if(position >= RANDOM_CHAR_LIMIT) |
84 | 0 | throw Decoding_Error("PEM: Malformed PEM header"); |
85 | 0 | else |
86 | 0 | position = 0; |
87 | 0 | } |
88 | 0 | position = 0; |
89 | 0 | while(position != PEM_HEADER2.length()) |
90 | 0 | { |
91 | 0 | uint8_t b; |
92 | 0 | if(!source.read_byte(b)) |
93 | 0 | throw Decoding_Error("PEM: No PEM header found"); |
94 | 0 | if(static_cast<char>(b) == PEM_HEADER2[position]) |
95 | 0 | ++position; |
96 | 0 | else if(position) |
97 | 0 | throw Decoding_Error("PEM: Malformed PEM header"); |
98 | | |
99 | 0 | if(position == 0) |
100 | 0 | label += static_cast<char>(b); |
101 | 0 | } |
102 | | |
103 | 0 | std::vector<char> b64; |
104 | |
|
105 | 0 | const std::string PEM_TRAILER = "-----END " + label + "-----"; |
106 | 0 | position = 0; |
107 | 0 | while(position != PEM_TRAILER.length()) |
108 | 0 | { |
109 | 0 | uint8_t b; |
110 | 0 | if(!source.read_byte(b)) |
111 | 0 | throw Decoding_Error("PEM: No PEM trailer found"); |
112 | 0 | if(static_cast<char>(b) == PEM_TRAILER[position]) |
113 | 0 | ++position; |
114 | 0 | else if(position) |
115 | 0 | throw Decoding_Error("PEM: Malformed PEM trailer"); |
116 | | |
117 | 0 | if(position == 0) |
118 | 0 | b64.push_back(b); |
119 | 0 | } |
120 | | |
121 | 0 | return base64_decode(b64.data(), b64.size()); |
122 | 0 | } |
123 | | |
124 | | secure_vector<uint8_t> decode_check_label(const std::string& pem, |
125 | | const std::string& label_want) |
126 | 0 | { |
127 | 0 | DataSource_Memory src(pem); |
128 | 0 | return decode_check_label(src, label_want); |
129 | 0 | } |
130 | | |
131 | | secure_vector<uint8_t> decode(const std::string& pem, std::string& label) |
132 | 0 | { |
133 | 0 | DataSource_Memory src(pem); |
134 | 0 | return decode(src, label); |
135 | 0 | } |
136 | | |
137 | | /* |
138 | | * Search for a PEM signature |
139 | | */ |
140 | | bool matches(DataSource& source, const std::string& extra, |
141 | | size_t search_range) |
142 | 0 | { |
143 | 0 | const std::string PEM_HEADER = "-----BEGIN " + extra; |
144 | |
|
145 | 0 | secure_vector<uint8_t> search_buf(search_range); |
146 | 0 | const size_t got = source.peek(search_buf.data(), search_buf.size(), 0); |
147 | |
|
148 | 0 | if(got < PEM_HEADER.length()) |
149 | 0 | return false; |
150 | | |
151 | 0 | size_t index = 0; |
152 | |
|
153 | 0 | for(size_t j = 0; j != got; ++j) |
154 | 0 | { |
155 | 0 | if(static_cast<char>(search_buf[j]) == PEM_HEADER[index]) |
156 | 0 | { |
157 | 0 | ++index; |
158 | 0 | } |
159 | 0 | else |
160 | 0 | { |
161 | 0 | index = 0; |
162 | 0 | } |
163 | |
|
164 | 0 | if(index == PEM_HEADER.size()) |
165 | 0 | { |
166 | 0 | return true; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | return false; |
171 | 0 | } |
172 | | |
173 | | } |