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