/src/boringssl/crypto/pem/pem_info.cc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/pem.h> |
16 | | |
17 | | #include <limits.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include <string_view> |
21 | | |
22 | | #include <openssl/dsa.h> |
23 | | #include <openssl/err.h> |
24 | | #include <openssl/evp.h> |
25 | | #include <openssl/mem.h> |
26 | | #include <openssl/obj.h> |
27 | | #include <openssl/rsa.h> |
28 | | #include <openssl/x509.h> |
29 | | |
30 | | #include "../mem_internal.h" |
31 | | #include "internal.h" |
32 | | |
33 | | |
34 | | using namespace bssl; |
35 | | |
36 | 0 | static X509_PKEY *X509_PKEY_new() { return New<X509_PKEY>(); } |
37 | | |
38 | 0 | static void X509_PKEY_free(X509_PKEY *x) { |
39 | 0 | if (x == nullptr) { |
40 | 0 | return; |
41 | 0 | } |
42 | | |
43 | 0 | EVP_PKEY_free(x->dec_pkey); |
44 | 0 | Delete(x); |
45 | 0 | } |
46 | | |
47 | 0 | static X509_INFO *X509_INFO_new() { return New<X509_INFO>(); } |
48 | | |
49 | 0 | void X509_INFO_free(X509_INFO *x) { |
50 | 0 | if (x == nullptr) { |
51 | 0 | return; |
52 | 0 | } |
53 | | |
54 | 0 | X509_free(x->x509); |
55 | 0 | X509_CRL_free(x->crl); |
56 | 0 | X509_PKEY_free(x->x_pkey); |
57 | 0 | OPENSSL_free(x->enc_data); |
58 | 0 | Delete(x); |
59 | 0 | } |
60 | | |
61 | | |
62 | | STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, |
63 | 0 | pem_password_cb *cb, void *u) { |
64 | 0 | BIO *b = BIO_new_fp(fp, BIO_NOCLOSE); |
65 | 0 | if (b == nullptr) { |
66 | 0 | OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); |
67 | 0 | return nullptr; |
68 | 0 | } |
69 | 0 | STACK_OF(X509_INFO) *ret = PEM_X509_INFO_read_bio(b, sk, cb, u); |
70 | 0 | BIO_free(b); |
71 | 0 | return ret; |
72 | 0 | } |
73 | | |
74 | | enum parse_result_t { |
75 | | parse_ok, |
76 | | parse_error, |
77 | | parse_new_entry, |
78 | | }; |
79 | | |
80 | | static enum parse_result_t parse_x509(X509_INFO *info, const uint8_t *data, |
81 | 0 | size_t len, int key_type) { |
82 | 0 | if (info->x509 != nullptr) { |
83 | 0 | return parse_new_entry; |
84 | 0 | } |
85 | 0 | info->x509 = d2i_X509(nullptr, &data, len); |
86 | 0 | return info->x509 != nullptr ? parse_ok : parse_error; |
87 | 0 | } |
88 | | |
89 | | static enum parse_result_t parse_x509_aux(X509_INFO *info, const uint8_t *data, |
90 | 0 | size_t len, int key_type) { |
91 | 0 | if (info->x509 != nullptr) { |
92 | 0 | return parse_new_entry; |
93 | 0 | } |
94 | 0 | info->x509 = d2i_X509_AUX(nullptr, &data, len); |
95 | 0 | return info->x509 != nullptr ? parse_ok : parse_error; |
96 | 0 | } |
97 | | |
98 | | static enum parse_result_t parse_crl(X509_INFO *info, const uint8_t *data, |
99 | 0 | size_t len, int key_type) { |
100 | 0 | if (info->crl != nullptr) { |
101 | 0 | return parse_new_entry; |
102 | 0 | } |
103 | 0 | info->crl = d2i_X509_CRL(nullptr, &data, len); |
104 | 0 | return info->crl != nullptr ? parse_ok : parse_error; |
105 | 0 | } |
106 | | |
107 | | static enum parse_result_t parse_key(X509_INFO *info, const uint8_t *data, |
108 | 0 | size_t len, int key_type) { |
109 | 0 | if (info->x_pkey != nullptr) { |
110 | 0 | return parse_new_entry; |
111 | 0 | } |
112 | 0 | info->x_pkey = X509_PKEY_new(); |
113 | 0 | if (info->x_pkey == nullptr) { |
114 | 0 | return parse_error; |
115 | 0 | } |
116 | 0 | info->x_pkey->dec_pkey = d2i_PrivateKey(key_type, nullptr, &data, len); |
117 | 0 | return info->x_pkey->dec_pkey != nullptr ? parse_ok : parse_error; |
118 | 0 | } |
119 | | |
120 | | STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, |
121 | 0 | pem_password_cb *cb, void *u) { |
122 | 0 | X509_INFO *info = nullptr; |
123 | 0 | UniquePtr<char> name; |
124 | 0 | UniquePtr<char> header; |
125 | 0 | Array<uint8_t> data; |
126 | 0 | int ok = 0; |
127 | 0 | STACK_OF(X509_INFO) *ret = nullptr; |
128 | |
|
129 | 0 | if (sk == nullptr) { |
130 | 0 | ret = sk_X509_INFO_new_null(); |
131 | 0 | if (ret == nullptr) { |
132 | 0 | return nullptr; |
133 | 0 | } |
134 | 0 | } else { |
135 | 0 | ret = sk; |
136 | 0 | } |
137 | 0 | size_t orig_num = sk_X509_INFO_num(ret); |
138 | |
|
139 | 0 | info = X509_INFO_new(); |
140 | 0 | if (info == nullptr) { |
141 | 0 | goto err; |
142 | 0 | } |
143 | | |
144 | 0 | for (;;) { |
145 | 0 | if (!PEM_read_bio_inner(bp, &name, &header, &data)) { |
146 | 0 | if (ERR_equals(ERR_peek_last_error(), ERR_LIB_PEM, PEM_R_NO_START_LINE)) { |
147 | 0 | ERR_clear_error(); |
148 | 0 | break; |
149 | 0 | } |
150 | 0 | goto err; |
151 | 0 | } |
152 | | |
153 | 0 | enum parse_result_t (*parse_function)(X509_INFO *, const uint8_t *, size_t, |
154 | 0 | int) = nullptr; |
155 | 0 | int key_type = EVP_PKEY_NONE; |
156 | 0 | std::string_view name_view = name.get(); |
157 | 0 | if (name_view == PEM_STRING_X509 || name_view == PEM_STRING_X509_OLD) { |
158 | 0 | parse_function = parse_x509; |
159 | 0 | } else if (name_view == PEM_STRING_X509_TRUSTED) { |
160 | 0 | parse_function = parse_x509_aux; |
161 | 0 | } else if (name_view == PEM_STRING_X509_CRL) { |
162 | 0 | parse_function = parse_crl; |
163 | 0 | } else if (name_view == PEM_STRING_RSA) { |
164 | 0 | parse_function = parse_key; |
165 | 0 | key_type = EVP_PKEY_RSA; |
166 | 0 | } else if (name_view == PEM_STRING_DSA) { |
167 | 0 | parse_function = parse_key; |
168 | 0 | key_type = EVP_PKEY_DSA; |
169 | 0 | } else if (name_view == PEM_STRING_ECPRIVATEKEY) { |
170 | 0 | parse_function = parse_key; |
171 | 0 | key_type = EVP_PKEY_EC; |
172 | 0 | } |
173 | | |
174 | | // If a private key has a header, assume it is encrypted. This function does |
175 | | // not decrypt private keys. |
176 | 0 | if (key_type != EVP_PKEY_NONE && strlen(header.get()) > 10) { |
177 | 0 | if (data.size() > INT_MAX) { |
178 | | // We need the data to fit in |info| which forces the size to |
179 | | // fit in one int type. |
180 | 0 | goto err; |
181 | 0 | } |
182 | 0 | if (info->x_pkey != nullptr) { |
183 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
184 | 0 | goto err; |
185 | 0 | } |
186 | 0 | info = X509_INFO_new(); |
187 | 0 | if (info == nullptr) { |
188 | 0 | goto err; |
189 | 0 | } |
190 | 0 | } |
191 | | // Use an empty key as a placeholder. |
192 | 0 | info->x_pkey = X509_PKEY_new(); |
193 | 0 | if (info->x_pkey == nullptr || |
194 | 0 | !PEM_get_EVP_CIPHER_INFO(header.get(), &info->enc_cipher)) { |
195 | 0 | goto err; |
196 | 0 | } |
197 | 0 | size_t size; |
198 | 0 | data.Release(reinterpret_cast<uint8_t **>(&info->enc_data), &size); |
199 | | // Safety: we checked that |size| <= |INT_MAX|. |
200 | 0 | info->enc_len = static_cast<int>(size); |
201 | 0 | } else if (parse_function != nullptr) { |
202 | 0 | EVP_CIPHER_INFO cipher; |
203 | 0 | size_t len = data.size(); |
204 | 0 | if (!PEM_get_EVP_CIPHER_INFO(header.get(), &cipher) || |
205 | 0 | !PEM_do_header(&cipher, data.data(), &len, cb, u)) { |
206 | 0 | goto err; |
207 | 0 | } |
208 | 0 | enum parse_result_t result = |
209 | 0 | parse_function(info, data.data(), len, key_type); |
210 | 0 | if (result == parse_new_entry) { |
211 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
212 | 0 | goto err; |
213 | 0 | } |
214 | 0 | info = X509_INFO_new(); |
215 | 0 | if (info == nullptr) { |
216 | 0 | goto err; |
217 | 0 | } |
218 | 0 | result = parse_function(info, data.data(), len, key_type); |
219 | 0 | } |
220 | 0 | if (result != parse_ok) { |
221 | 0 | OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); |
222 | 0 | goto err; |
223 | 0 | } |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | | // Push the last entry on the stack if not empty. |
228 | 0 | if (info->x509 != nullptr || info->crl != nullptr || |
229 | 0 | info->x_pkey != nullptr || info->enc_data != nullptr) { |
230 | 0 | if (!sk_X509_INFO_push(ret, info)) { |
231 | 0 | goto err; |
232 | 0 | } |
233 | 0 | info = nullptr; |
234 | 0 | } |
235 | | |
236 | 0 | ok = 1; |
237 | |
|
238 | 0 | err: |
239 | 0 | X509_INFO_free(info); |
240 | 0 | if (!ok) { |
241 | 0 | while (sk_X509_INFO_num(ret) > orig_num) { |
242 | 0 | X509_INFO_free(sk_X509_INFO_pop(ret)); |
243 | 0 | } |
244 | 0 | if (ret != sk) { |
245 | 0 | sk_X509_INFO_free(ret); |
246 | 0 | } |
247 | 0 | ret = nullptr; |
248 | 0 | } |
249 | 0 | return ret; |
250 | 0 | } |