1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
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 // http://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 "ssl_x509.h"
16 #include "ssl_methods.h"
17 #include "ssl_dbg.h"
18 #include "ssl_port.h"
19 #include "ssl.h"
20
21 /**
22 * @brief show X509 certification information
23 */
__X509_show_info(X509 * x)24 int __X509_show_info(X509 *x)
25 {
26 return X509_METHOD_CALL(show_info, x);
27 }
28
29 /**
30 * @brief create a X509 certification object according to input X509 certification
31 */
__X509_new(X509 * ix)32 X509* __X509_new(X509 *ix)
33 {
34 int ret;
35 X509 *x;
36
37 x = ssl_mem_zalloc(sizeof(X509));
38 if (!x) {
39 SSL_DEBUG(SSL_X509_ERROR_LEVEL, "no enough memory > (x)");
40 goto no_mem;
41 }
42
43 x->ref_counter = 1;
44
45 if (ix && ix->method)
46 x->method = ix->method;
47 else
48 x->method = X509_method();
49
50 ret = X509_METHOD_CALL(new, x, ix);
51 if (ret) {
52 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(new) return %d", ret);
53 goto failed;
54 }
55
56 return x;
57
58 failed:
59 ssl_mem_free(x);
60 no_mem:
61 return NULL;
62 }
63
64 /**
65 * @brief create a X509 certification object
66 */
X509_new(void)67 X509* X509_new(void)
68 {
69 return __X509_new(NULL);
70 }
71
72 /**
73 * @brief free a X509 certification object
74 */
X509_free(X509 * x)75 void X509_free(X509 *x)
76 {
77 SSL_ASSERT3(x);
78
79 if (--x->ref_counter > 0) {
80 return;
81 }
82
83 X509_METHOD_CALL(free, x);
84
85 ssl_mem_free(x);
86 };
87
88 /**
89 * @brief load a character certification context into system context. If '*cert' is pointed to the
90 * certification, then load certification into it. Or create a new X509 certification object
91 */
d2i_X509(X509 ** cert,const unsigned char * buffer,long len)92 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len)
93 {
94 int m = 0;
95 int ret;
96 X509 *x;
97
98 SSL_ASSERT2(buffer);
99 SSL_ASSERT2(len);
100
101 if (cert && *cert) {
102 x = *cert;
103 } else {
104 x = X509_new();
105 if (!x) {
106 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL");
107 goto failed1;
108 }
109 m = 1;
110 }
111
112 ret = X509_METHOD_CALL(load, x, buffer, len);
113 if (ret) {
114 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
115 goto failed2;
116 }
117
118 return x;
119
120 failed2:
121 if (m)
122 X509_free(x);
123 failed1:
124 return NULL;
125 }
126
127 /**
128 * @brief return SSL X509 verify parameters
129 */
130
SSL_get0_param(SSL * ssl)131 X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
132 {
133 return &ssl->param;
134 }
135
136 /**
137 * @brief set X509 host verification flags
138 */
139
X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM * param,unsigned long flags)140 int X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
141 unsigned long flags)
142 {
143 /* flags not supported yet */
144 return 0;
145 }
146
147 /**
148 * @brief clear X509 host verification flags
149 */
150
X509_VERIFY_PARAM_clear_hostflags(X509_VERIFY_PARAM * param,unsigned long flags)151 int X509_VERIFY_PARAM_clear_hostflags(X509_VERIFY_PARAM *param,
152 unsigned long flags)
153 {
154 /* flags not supported yet */
155 return 0;
156 }
157
158 /**
159 * @brief set SSL context client CA certification
160 */
SSL_CTX_add_client_CA(SSL_CTX * ctx,X509 * x)161 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
162 {
163 SSL_ASSERT1(ctx);
164 SSL_ASSERT1(x);
165
166 if (ctx->client_CA == x)
167 return 1;
168
169 X509_free(ctx->client_CA);
170
171 ctx->client_CA = x;
172
173 return 1;
174 }
175
176 /**
177 * @brief add CA client certification into the SSL
178 */
SSL_add_client_CA(SSL * ssl,X509 * x)179 int SSL_add_client_CA(SSL *ssl, X509 *x)
180 {
181 SSL_ASSERT1(ssl);
182 SSL_ASSERT1(x);
183
184 if (ssl->client_CA == x)
185 return 1;
186
187 X509_free(ssl->client_CA);
188
189 ssl->client_CA = x;
190
191 return 1;
192 }
193
194 /**
195 * @brief set the SSL context certification
196 */
SSL_CTX_use_certificate(SSL_CTX * ctx,X509 * x)197 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
198 {
199 SSL_ASSERT1(ctx);
200 SSL_ASSERT1(x);
201
202 if (ctx->cert->x509 == x)
203 return 1;
204
205 X509_free(ctx->cert->x509);
206
207 ctx->cert->x509 = x;
208 x->ref_counter++;
209
210 return 1;
211 }
212
213 /**
214 * @brief set the SSL certification
215 */
SSL_use_certificate(SSL * ssl,X509 * x)216 int SSL_use_certificate(SSL *ssl, X509 *x)
217 {
218 SSL_ASSERT1(ssl);
219 SSL_ASSERT1(x);
220
221 if (ssl->cert->x509 == x)
222 return 1;
223
224 X509_free(ssl->cert->x509);
225
226 ssl->cert->x509 = x;
227
228 return 1;
229 }
230
SSL_CTX_add_extra_chain_cert(SSL_CTX * ctx,X509 * x)231 long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x)
232 {
233 return SSL_CTX_use_certificate(ctx, x);
234 }
235
236 /**
237 * @brief get the SSL certification point
238 */
SSL_get_certificate(const SSL * ssl)239 X509 *SSL_get_certificate(const SSL *ssl)
240 {
241 SSL_ASSERT2(ssl);
242
243 return ssl->cert->x509;
244 }
245
246 /**
247 * @brief load certification into the SSL context
248 */
SSL_CTX_use_certificate_ASN1(SSL_CTX * ctx,int len,const unsigned char * d)249 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len,
250 const unsigned char *d)
251 {
252 int ret;
253 X509 *x;
254
255 x = d2i_X509(NULL, d, len);
256 if (!x) {
257 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
258 goto failed1;
259 }
260
261 ret = SSL_CTX_use_certificate(ctx, x); // This uses the "x" so increments ref_count
262 if (!ret) {
263 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret);
264 goto failed2;
265 }
266
267 X509_free(x); // decrements ref_count, so in case of happy flow doesn't free the "x"
268 return 1;
269
270 failed2:
271 X509_free(x);
272 failed1:
273 return 0;
274 }
275
276 /**
277 * @brief load certification into the SSL
278 */
SSL_use_certificate_ASN1(SSL * ssl,int len,const unsigned char * d)279 int SSL_use_certificate_ASN1(SSL *ssl, int len,
280 const unsigned char *d)
281 {
282 int ret;
283 X509 *x;
284
285 x = d2i_X509(NULL, d, len);
286 if (!x) {
287 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
288 goto failed1;
289 }
290
291 ret = SSL_use_certificate(ssl, x);
292 if (!ret) {
293 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_certificate() return %d", ret);
294 goto failed2;
295 }
296
297 return 1;
298
299 failed2:
300 X509_free(x);
301 failed1:
302 return 0;
303 }
304
305 /**
306 * @brief load the certification file into SSL context
307 */
SSL_CTX_use_certificate_file(SSL_CTX * ctx,const char * file,int type)308 int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
309 {
310 return 0;
311 }
312
313 /**
314 * @brief load the certification file into SSL
315 */
SSL_use_certificate_file(SSL * ssl,const char * file,int type)316 int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
317 {
318 return 0;
319 }
320
321 /**
322 * @brief get peer certification
323 */
SSL_get_peer_certificate(const SSL * ssl)324 X509 *SSL_get_peer_certificate(const SSL *ssl)
325 {
326 SSL_ASSERT2(ssl);
327
328 return ssl->session->peer;
329 }
330
331 /**
332 * @brief set SSL context client CA certification
333 */
X509_STORE_add_cert(X509_STORE * store,X509 * x)334 int X509_STORE_add_cert(X509_STORE *store, X509 *x) {
335
336 x->ref_counter++;
337
338 SSL_CTX *ctx = (SSL_CTX *)store;
339 SSL_ASSERT1(ctx);
340 SSL_ASSERT1(x);
341
342 if (ctx->client_CA == x) {
343 return 1;
344 }
345
346 if (ctx->client_CA!=NULL) {
347 X509_free(ctx->client_CA);
348 }
349
350 ctx->client_CA = x;
351 return 1;
352 }
353
354 /**
355 * @brief load a character certification context into system context.
356 *
357 * If '*cert' is pointed to the certification, then load certification
358 * into it, or create a new X509 certification object.
359 */
PEM_read_bio_X509(BIO * bp,X509 ** cert,pem_password_cb cb,void * u)360 X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, pem_password_cb cb, void *u) {
361 int m = 0;
362 int ret;
363 X509 *x;
364
365 SSL_ASSERT2(BIO_method_type(bp) & BIO_TYPE_MEM);
366 if (bp->data == NULL || bp->dlen == 0) {
367 return NULL;
368 }
369 if (cert && *cert) {
370 x = *cert;
371 } else {
372 x = X509_new();
373 if (!x) {
374 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL");
375 goto failed;
376 }
377 m = 1;
378 }
379
380 ret = X509_METHOD_CALL(load, x, bp->data, bp->dlen);
381 if (ret) {
382 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
383 goto failed;
384 }
385
386 // If buffer successfully created a X509 from the bio, mark the buffer as consumed
387 bp->data = NULL;
388 bp->dlen = 0;
389 return x;
390
391 failed:
392 if (m) {
393 X509_free(x);
394 }
395
396 return NULL;
397 }
398
PEM_read_bio_X509_AUX(BIO * bp,X509 ** cert,pem_password_cb * cb,void * u)399 X509 *PEM_read_bio_X509_AUX(BIO *bp, X509 **cert, pem_password_cb *cb, void *u)
400 {
401 return PEM_read_bio_X509(bp, cert, cb, u);
402 }
403
404 /**
405 * @brief get the SSL context object X509 certification storage
406 */
SSL_CTX_get_cert_store(const SSL_CTX * ctx)407 X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
408 return (X509_STORE *)ctx;
409 }
410