Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / btls / btls-x509.c
1 //
2 //  btls-x509.c
3 //  MonoBtls
4 //
5 //  Created by Martin Baulig on 14/11/15.
6 //  Copyright (c) 2015 Xamarin. All rights reserved.
7 //
8
9 #include <btls-x509.h>
10 #include <openssl/x509v3.h>
11 #include <openssl/pkcs12.h>
12
13 MONO_API X509 *
14 mono_btls_x509_from_data (const void *buf, int len, MonoBtlsX509Format format)
15 {
16         BIO *bio;
17         X509 *cert = NULL;
18
19         bio = BIO_new_mem_buf ((void *)buf, len);
20         switch (format) {
21                 case MONO_BTLS_X509_FORMAT_DER:
22                         cert = d2i_X509_bio (bio, NULL);
23                         break;
24                 case MONO_BTLS_X509_FORMAT_PEM:
25                         cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
26                         break;
27         }
28         BIO_free (bio);
29         return cert;
30 }
31
32 MONO_API X509 *
33 mono_btls_x509_up_ref (X509 *x509)
34 {
35         X509_up_ref (x509);
36         return x509;
37 }
38
39 MONO_API void
40 mono_btls_x509_free (X509 *x509)
41 {
42         X509_free (x509);
43 }
44
45 MONO_API X509 *
46 mono_btls_x509_dup (X509 *x509)
47 {
48         return X509_dup (x509);
49 }
50
51 MONO_API MonoBtlsX509Name *
52 mono_btls_x509_get_subject_name (X509 *x509)
53 {
54         return mono_btls_x509_name_copy (X509_get_subject_name (x509));
55 }
56
57 MONO_API MonoBtlsX509Name *
58 mono_btls_x509_get_issuer_name (X509 *x509)
59 {
60         return mono_btls_x509_name_copy (X509_get_issuer_name (x509));
61 }
62
63 MONO_API int
64 mono_btls_x509_get_subject_name_string (X509 *name, char *buffer, int size)
65 {
66         *buffer = 0;
67         return X509_NAME_oneline (X509_get_subject_name (name), buffer, size) != NULL;
68 }
69
70 MONO_API int
71 mono_btls_x509_get_issuer_name_string (X509 *name, char *buffer, int size)
72 {
73         *buffer = 0;
74         return X509_NAME_oneline (X509_get_issuer_name (name), buffer, size) != NULL;
75 }
76
77 MONO_API int
78 mono_btls_x509_get_raw_data (X509 *x509, BIO *bio, MonoBtlsX509Format format)
79 {
80         switch (format) {
81                 case MONO_BTLS_X509_FORMAT_DER:
82                         return i2d_X509_bio (bio, x509);
83                 case MONO_BTLS_X509_FORMAT_PEM:
84                         return PEM_write_bio_X509 (bio, x509);
85                 default:
86                         return 0;
87         }
88 }
89
90 MONO_API int
91 mono_btls_x509_cmp (const X509 *a, const X509 *b)
92 {
93         return X509_cmp (a, b);
94 }
95
96 MONO_API int
97 mono_btls_x509_get_hash (X509 *x509, const void **data)
98 {
99         X509_check_purpose (x509, -1, 0);
100         *data = x509->sha1_hash;
101         return SHA_DIGEST_LENGTH;
102 }
103
104 MONO_API int64_t
105 mono_btls_x509_get_not_before (X509 *x509)
106 {
107         return mono_btls_util_asn1_time_to_ticks (X509_get_notBefore (x509));
108 }
109
110 MONO_API int64_t
111 mono_btls_x509_get_not_after (X509 *x509)
112 {
113         return mono_btls_util_asn1_time_to_ticks (X509_get_notAfter (x509));
114 }
115
116 MONO_API int
117 mono_btls_x509_get_public_key (X509 *x509, BIO *bio)
118 {
119         EVP_PKEY *pkey;
120         uint8_t *data = NULL;
121         int ret;
122
123         pkey = X509_get_pubkey (x509);
124         if (!pkey)
125                 return -1;
126
127         ret = i2d_PublicKey (pkey, &data);
128
129         if (ret > 0 && data) {
130                 ret = BIO_write (bio, data, ret);
131                 OPENSSL_free (data);
132         }
133
134         EVP_PKEY_free (pkey);
135         return ret;
136 }
137
138 MONO_API int
139 mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_style)
140 {
141         ASN1_INTEGER *serial;
142         unsigned char *temp, *p;
143         int len, idx;
144
145         serial = X509_get_serialNumber (x509);
146         if (serial->length == 0 || serial->length+1 > size)
147                 return 0;
148
149         if (!mono_style) {
150                 memcpy (buffer, serial->data, serial->length);
151                 return serial->length;
152         }
153
154         temp = OPENSSL_malloc (serial->length + 1);
155         if (!temp)
156                 return 0;
157
158         p = temp;
159         len = i2c_ASN1_INTEGER (serial, &p);
160
161         if (!len) {
162                 OPENSSL_free (temp);
163                 return 0;
164         }
165
166         for (idx = 0; idx < len; idx++) {
167                 buffer [idx] = *(--p);
168         }
169         buffer [len] = 0;
170
171         OPENSSL_free (temp);
172         return len;
173 }
174
175 MONO_API int
176 mono_btls_x509_get_public_key_algorithm (X509 *x509, char *buffer, int size)
177 {
178         X509_PUBKEY *pkey;
179         ASN1_OBJECT *ppkalg;
180         int ret;
181
182         *buffer = 0;
183         pkey = X509_get_X509_PUBKEY (x509);
184         if (!pkey)
185                 return 0;
186
187         ret = X509_PUBKEY_get0_param (&ppkalg, NULL, NULL, NULL, pkey);
188         if (!ret || !ppkalg)
189                 return ret;
190
191         return OBJ_obj2txt (buffer, size, ppkalg, 1);
192 }
193
194 MONO_API int
195 mono_btls_x509_get_version (X509 *x509)
196 {
197         return (int)X509_get_version (x509) + 1;
198 }
199
200 MONO_API int
201 mono_btls_x509_get_signature_algorithm (X509 *x509, char *buffer, int size)
202 {
203         const ASN1_OBJECT *obj;
204         int nid;
205
206         *buffer = 0;
207
208         nid = X509_get_signature_nid (x509);
209
210         obj = OBJ_nid2obj (nid);
211         if (!obj)
212                 return 0;
213
214         return OBJ_obj2txt (buffer, size, obj, 1);
215 }
216
217 MONO_API int
218 mono_btls_x509_get_public_key_asn1 (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
219 {
220         X509_PUBKEY *pkey;
221         ASN1_OBJECT *ppkalg;
222         const unsigned char *pk;
223         int pk_len;
224         int ret;
225
226         if (out_oid)
227                 *out_oid = 0;
228
229         pkey = X509_get_X509_PUBKEY (x509);
230         if (!pkey || !pkey->public_key)
231                 return 0;
232
233         ret = X509_PUBKEY_get0_param (&ppkalg, &pk, &pk_len, NULL, pkey);
234         if (ret != 1 || !ppkalg || !pk)
235                 return 0;
236
237         if (out_oid) {
238                 OBJ_obj2txt (out_oid, oid_len, ppkalg, 1);
239         }
240
241         if (buffer) {
242                 *size = pk_len;
243                 *buffer = OPENSSL_malloc (pk_len);
244                 if (!*buffer)
245                         return 0;
246
247                 memcpy (*buffer, pk, pk_len);
248         }
249
250         return 1;
251
252 }
253
254 MONO_API int
255 mono_btls_x509_get_public_key_parameters (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
256 {
257         X509_PUBKEY *pkey;
258         X509_ALGOR *algor;
259         ASN1_OBJECT *paobj;
260         int ptype;
261         void *pval;
262         int ret;
263
264         if (out_oid)
265                 *out_oid = 0;
266
267         pkey = X509_get_X509_PUBKEY (x509);
268
269         ret = X509_PUBKEY_get0_param (NULL, NULL, NULL, &algor, pkey);
270         if (ret != 1 || !algor)
271                 return 0;
272
273         X509_ALGOR_get0 (&paobj, &ptype, &pval, algor);
274
275         if (ptype != V_ASN1_NULL && ptype != V_ASN1_SEQUENCE)
276                 return 0;
277
278         if (ptype == V_ASN1_NULL) {
279                 uint8_t *ptr;
280
281                 *size = 2;
282                 *buffer = OPENSSL_malloc (2);
283                 if (!*buffer)
284                         return 0;
285
286                 ptr = *buffer;
287                 *ptr++ = 0x05;
288                 *ptr++ = 0x00;
289
290                 if (out_oid)
291                         OBJ_obj2txt (out_oid, oid_len, paobj, 1);
292
293                 return 1;
294         } else if (ptype == V_ASN1_SEQUENCE) {
295                 ASN1_STRING *pstr = pval;
296
297                 *size = pstr->length;
298                 *buffer = OPENSSL_malloc (pstr->length);
299                 if (!*buffer)
300                         return 0;
301
302                 memcpy (*buffer, pstr->data, pstr->length);
303
304                 if (out_oid)
305                         OBJ_obj2txt (out_oid, oid_len, paobj, 1);
306
307                 return 1;
308         } else {
309                 return 0;
310         }
311 }
312
313 MONO_API EVP_PKEY *
314 mono_btls_x509_get_pubkey (X509 *x509)
315 {
316         return X509_get_pubkey (x509);
317 }
318
319 MONO_API int
320 mono_btls_x509_get_subject_key_identifier (X509 *x509, uint8_t **buffer, int *size)
321 {
322         ASN1_OCTET_STRING *skid;
323
324         *size = 0;
325         *buffer = NULL;
326
327         if (X509_get_version (x509) != 2)
328                 return 0;
329
330         skid = X509_get_ext_d2i (x509, NID_subject_key_identifier, NULL, NULL);
331         if (!skid)
332                 return 0;
333
334         *size = skid->length;
335         *buffer = OPENSSL_malloc (*size);
336         if (!*buffer)
337                 return 0;
338
339         memcpy (*buffer, skid->data, *size);
340         return 1;
341 }
342
343 MONO_API int
344 mono_btls_x509_print (X509 *x509, BIO *bio)
345 {
346         return X509_print_ex (bio, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
347 }
348
349 static int
350 get_trust_nid (MonoBtlsX509Purpose purpose)
351 {
352         switch (purpose) {
353                 case MONO_BTLS_X509_PURPOSE_SSL_CLIENT:
354                         return NID_client_auth;
355                 case MONO_BTLS_X509_PURPOSE_SSL_SERVER:
356                         return NID_server_auth;
357                 default:
358                         return 0;
359         }
360 }
361
362 MONO_API int
363 mono_btls_x509_add_trust_object (X509 *x509, MonoBtlsX509Purpose purpose)
364 {
365         ASN1_OBJECT *trust;
366         int nid;
367
368         nid = get_trust_nid (purpose);
369         if (!nid)
370                 return 0;
371
372         trust = ASN1_OBJECT_new ();
373         if (!trust)
374                 return 0;
375
376         trust->nid = nid;
377         return X509_add1_trust_object (x509, trust);
378 }
379
380 MONO_API int
381 mono_btls_x509_add_reject_object (X509 *x509, MonoBtlsX509Purpose purpose)
382 {
383         ASN1_OBJECT *reject;
384         int nid;
385
386         nid = get_trust_nid (purpose);
387         if (!nid)
388                 return 0;
389
390         reject = ASN1_OBJECT_new ();
391         if (!reject)
392                 return 0;
393
394         reject->nid = nid;
395         return X509_add1_reject_object (x509, reject);
396 }
397
398 MONO_API int
399 mono_btls_x509_add_explicit_trust (X509 *x509, MonoBtlsX509TrustKind kind)
400 {
401         int ret = 0;
402
403         if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_ALL) != 0)
404                 kind |= MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT | MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER;
405
406         if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_ALL) != 0)
407                 kind |= MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT | MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER;
408
409
410         if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT) != 0) {
411                 ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
412                 if (!ret)
413                         return ret;
414         }
415
416         if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER) != 0) {
417                 ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
418                 if (!ret)
419                         return ret;
420         }
421
422         if (ret) {
423                 // Ignore any MONO_BTLS_X509_TRUST_KIND_TRUST_* settings if we added
424                 // any kind of MONO_BTLS_X509_TRUST_KIND_REJECT_* before.
425                 return ret;
426         }
427
428         if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT) != 0) {
429                 ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
430                 if (!ret)
431                         return ret;
432         }
433
434         if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER) != 0) {
435                 ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
436                 if (!ret)
437                         return ret;
438         }
439
440         return ret;
441 }