/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 { |
14 | | |
15 | | namespace PEM_Code { |
16 | | |
17 | | namespace { |
18 | | |
19 | | std::string linewrap(size_t width, const std::string& in) |
20 | 0 | { |
21 | 0 | std::string out; |
22 | 0 | for(size_t i = 0; i != in.size(); ++i) |
23 | 0 | { |
24 | 0 | if(i > 0 && i % width == 0) |
25 | 0 | { |
26 | 0 | out.push_back('\n'); |
27 | 0 | } |
28 | 0 | out.push_back(in[i]); |
29 | 0 | } |
30 | 0 | if(out.size() > 0 && out[out.size()-1] != '\n') |
31 | 0 | { |
32 | 0 | out.push_back('\n'); |
33 | 0 | } |
34 | 0 |
|
35 | 0 | return out; |
36 | 0 | } |
37 | | |
38 | | } |
39 | | |
40 | | /* |
41 | | * PEM encode BER/DER-encoded objects |
42 | | */ |
43 | | std::string encode(const uint8_t der[], size_t length, const std::string& label, size_t width) |
44 | 0 | { |
45 | 0 | const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n"; |
46 | 0 | const std::string PEM_TRAILER = "-----END " + label + "-----\n"; |
47 | 0 |
|
48 | 0 | return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER); |
49 | 0 | } |
50 | | |
51 | | /* |
52 | | * Decode PEM down to raw BER/DER |
53 | | */ |
54 | | secure_vector<uint8_t> decode_check_label(DataSource& source, |
55 | | const std::string& label_want) |
56 | 0 | { |
57 | 0 | std::string label_got; |
58 | 0 | secure_vector<uint8_t> ber = decode(source, label_got); |
59 | 0 | if(label_got != label_want) |
60 | 0 | throw Decoding_Error("PEM: Label mismatch, wanted " + label_want + |
61 | 0 | ", got " + label_got); |
62 | 0 | return ber; |
63 | 0 | } |
64 | | |
65 | | /* |
66 | | * Decode PEM down to raw BER/DER |
67 | | */ |
68 | | secure_vector<uint8_t> decode(DataSource& source, std::string& label) |
69 | 6.17k | { |
70 | 6.17k | const size_t RANDOM_CHAR_LIMIT = 8; |
71 | 6.17k | |
72 | 6.17k | label.clear(); |
73 | 6.17k | |
74 | 6.17k | const std::string PEM_HEADER1 = "-----BEGIN "; |
75 | 6.17k | const std::string PEM_HEADER2 = "-----"; |
76 | 6.17k | size_t position = 0; |
77 | 6.17k | |
78 | 171k | while(position != PEM_HEADER1.length()) |
79 | 165k | { |
80 | 165k | uint8_t b; |
81 | 165k | if(!source.read_byte(b)) |
82 | 178 | throw Decoding_Error("PEM: No PEM header found"); |
83 | 165k | if(b == PEM_HEADER1[position]) |
84 | 67.8k | ++position; |
85 | 97.8k | else if(position >= RANDOM_CHAR_LIMIT) |
86 | 7 | throw Decoding_Error("PEM: Malformed PEM header"); |
87 | 97.8k | else |
88 | 97.8k | position = 0; |
89 | 165k | } |
90 | 6.17k | position = 0; |
91 | 162k | while(position != PEM_HEADER2.length()) |
92 | 156k | { |
93 | 156k | uint8_t b; |
94 | 156k | if(!source.read_byte(b)) |
95 | 136 | throw Decoding_Error("PEM: No PEM header found"); |
96 | 156k | if(b == PEM_HEADER2[position]) |
97 | 29.2k | ++position; |
98 | 127k | else if(position) |
99 | 27 | throw Decoding_Error("PEM: Malformed PEM header"); |
100 | 156k | |
101 | 156k | if(position == 0) |
102 | 127k | label += static_cast<char>(b); |
103 | 156k | } |
104 | 5.99k | |
105 | 5.99k | std::vector<char> b64; |
106 | 5.82k | |
107 | 5.82k | const std::string PEM_TRAILER = "-----END " + label + "-----"; |
108 | 5.82k | position = 0; |
109 | 6.16M | while(position != PEM_TRAILER.length()) |
110 | 6.15M | { |
111 | 6.15M | uint8_t b; |
112 | 6.15M | if(!source.read_byte(b)) |
113 | 302 | throw Decoding_Error("PEM: No PEM trailer found"); |
114 | 6.15M | if(b == PEM_TRAILER[position]) |
115 | 151k | ++position; |
116 | 6.00M | else if(position) |
117 | 111 | throw Decoding_Error("PEM: Malformed PEM trailer"); |
118 | 6.15M | |
119 | 6.15M | if(position == 0) |
120 | 6.00M | b64.push_back(b); |
121 | 6.15M | } |
122 | 5.82k | |
123 | 5.82k | return base64_decode(b64.data(), b64.size()); |
124 | 5.82k | } |
125 | | |
126 | | secure_vector<uint8_t> decode_check_label(const std::string& pem, |
127 | | const std::string& label_want) |
128 | 0 | { |
129 | 0 | DataSource_Memory src(pem); |
130 | 0 | return decode_check_label(src, label_want); |
131 | 0 | } |
132 | | |
133 | | secure_vector<uint8_t> decode(const std::string& pem, std::string& label) |
134 | 0 | { |
135 | 0 | DataSource_Memory src(pem); |
136 | 0 | return decode(src, label); |
137 | 0 | } |
138 | | |
139 | | /* |
140 | | * Search for a PEM signature |
141 | | */ |
142 | | bool matches(DataSource& source, const std::string& extra, |
143 | | size_t search_range) |
144 | 23.9k | { |
145 | 23.9k | const std::string PEM_HEADER = "-----BEGIN " + extra; |
146 | 23.9k | |
147 | 23.9k | secure_vector<uint8_t> search_buf(search_range); |
148 | 23.9k | size_t got = source.peek(search_buf.data(), search_buf.size(), 0); |
149 | 23.9k | |
150 | 23.9k | if(got < PEM_HEADER.length()) |
151 | 1.38k | return false; |
152 | 22.5k | |
153 | 22.5k | size_t index = 0; |
154 | 22.5k | |
155 | 9.65M | for(size_t j = 0; j != got; ++j) |
156 | 9.62M | { |
157 | 9.62M | if(search_buf[j] == PEM_HEADER[index]) |
158 | 42.3k | ++index; |
159 | 9.58M | else |
160 | 9.58M | index = 0; |
161 | 9.62M | if(index == PEM_HEADER.size()) |
162 | 163 | return true; |
163 | 9.62M | } |
164 | 22.5k | return false; |
165 | 22.5k | } |
166 | | |
167 | | } |
168 | | |
169 | | } |