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