1 /*
2  * XML Security Library (http://www.aleksey.com/xmlsec).
3  *
4  *
5  *
6  * This is free software; see Copyright file in the source
7  * distribution for preciese wording.
8  *
9  * Copyright (C) 2010-2016 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
10  */
11 /**
12  * SECTION:x509utils
13  * @Short_description: X509 certificates support functions for GnuTLS.
14  * @Stability: Private
15  *
16  */
17 
18 #include "globals.h"
19 
20 #ifndef XMLSEC_NO_X509
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <time.h>
28 
29 #include <libxml/tree.h>
30 
31 
32 
33 #include <gnutls/gnutls.h>
34 #include <gnutls/x509.h>
35 #include <gnutls/pkcs12.h>
36 
37 #include <xmlsec/xmlsec.h>
38 #include <xmlsec/xmltree.h>
39 #include <xmlsec/keys.h>
40 #include <xmlsec/keyinfo.h>
41 #include <xmlsec/keysmngr.h>
42 #include <xmlsec/x509.h>
43 #include <xmlsec/base64.h>
44 #include <xmlsec/errors.h>
45 #include <xmlsec/private.h>
46 
47 #include <xmlsec/gnutls/crypto.h>
48 #include <xmlsec/gnutls/x509.h>
49 
50 #include "x509utils.h"
51 
52 
53 /**************************************************************************
54  *
55  * X509 crt list
56  *
57  *****************************************************************************/
58 static xmlSecPtr        xmlSecGnuTLSX509CrtListDuplicateItem    (xmlSecPtr ptr);
59 static void             xmlSecGnuTLSX509CrtListDestroyItem      (xmlSecPtr ptr);
60 static void             xmlSecGnuTLSX509CrtListDebugDumpItem    (xmlSecPtr ptr,
61                                                                  FILE* output);
62 static void             xmlSecGnuTLSX509CrtListDebugXmlDumpItem (xmlSecPtr ptr,
63                                                                  FILE* output);
64 
65 static xmlSecPtrListKlass xmlSecGnuTLSX509CrtListKlass = {
66     BAD_CAST "gnutls-x509-crt-list",
67     xmlSecGnuTLSX509CrtListDuplicateItem,       /* xmlSecPtrDuplicateItemMethod duplicateItem; */
68     xmlSecGnuTLSX509CrtListDestroyItem,         /* xmlSecPtrDestroyItemMethod destroyItem; */
69     xmlSecGnuTLSX509CrtListDebugDumpItem,       /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
70     xmlSecGnuTLSX509CrtListDebugXmlDumpItem,    /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
71 };
72 
73 xmlSecPtrListId
xmlSecGnuTLSX509CrtListGetKlass(void)74 xmlSecGnuTLSX509CrtListGetKlass(void) {
75     return(&xmlSecGnuTLSX509CrtListKlass);
76 }
77 
78 static xmlSecPtr
xmlSecGnuTLSX509CrtListDuplicateItem(xmlSecPtr ptr)79 xmlSecGnuTLSX509CrtListDuplicateItem(xmlSecPtr ptr) {
80     xmlSecAssert2(ptr != NULL, NULL);
81 
82     return xmlSecGnuTLSX509CertDup((gnutls_x509_crt_t)ptr);
83 }
84 
85 static void
xmlSecGnuTLSX509CrtListDestroyItem(xmlSecPtr ptr)86 xmlSecGnuTLSX509CrtListDestroyItem(xmlSecPtr ptr) {
87     xmlSecAssert(ptr != NULL);
88 
89     gnutls_x509_crt_deinit((gnutls_x509_crt_t)ptr);
90 }
91 
92 static void
xmlSecGnuTLSX509CrtListDebugDumpItem(xmlSecPtr ptr,FILE * output)93 xmlSecGnuTLSX509CrtListDebugDumpItem(xmlSecPtr ptr, FILE* output) {
94     xmlSecAssert(ptr != NULL);
95     xmlSecAssert(output != NULL);
96 
97     xmlSecGnuTLSX509CertDebugDump((gnutls_x509_crt_t)ptr, output);
98 }
99 
100 
101 static void
xmlSecGnuTLSX509CrtListDebugXmlDumpItem(xmlSecPtr ptr,FILE * output)102 xmlSecGnuTLSX509CrtListDebugXmlDumpItem(xmlSecPtr ptr, FILE* output) {
103     xmlSecAssert(ptr != NULL);
104     xmlSecAssert(output != NULL);
105 
106     xmlSecGnuTLSX509CertDebugXmlDump((gnutls_x509_crt_t)ptr, output);
107 }
108 
109 /**************************************************************************
110  *
111  * X509 crl list
112  *
113  *****************************************************************************/
114 static xmlSecPtr        xmlSecGnuTLSX509CrlListDuplicateItem    (xmlSecPtr ptr);
115 static void             xmlSecGnuTLSX509CrlListDestroyItem      (xmlSecPtr ptr);
116 static void             xmlSecGnuTLSX509CrlListDebugDumpItem    (xmlSecPtr ptr,
117                                                                  FILE* output);
118 static void             xmlSecGnuTLSX509CrlListDebugXmlDumpItem (xmlSecPtr ptr,
119                                                                  FILE* output);
120 
121 static xmlSecPtrListKlass xmlSecGnuTLSX509CrlListKlass = {
122     BAD_CAST "gnutls-x509-crl-list",
123     xmlSecGnuTLSX509CrlListDuplicateItem,       /* xmlSecPtrDuplicateItemMethod duplicateItem; */
124     xmlSecGnuTLSX509CrlListDestroyItem,         /* xmlSecPtrDestroyItemMethod destroyItem; */
125     xmlSecGnuTLSX509CrlListDebugDumpItem,       /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
126     xmlSecGnuTLSX509CrlListDebugXmlDumpItem,    /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
127 };
128 
129 xmlSecPtrListId
xmlSecGnuTLSX509CrlListGetKlass(void)130 xmlSecGnuTLSX509CrlListGetKlass(void) {
131     return(&xmlSecGnuTLSX509CrlListKlass);
132 }
133 
134 static xmlSecPtr
xmlSecGnuTLSX509CrlListDuplicateItem(xmlSecPtr ptr)135 xmlSecGnuTLSX509CrlListDuplicateItem(xmlSecPtr ptr) {
136     xmlSecAssert2(ptr != NULL, NULL);
137 
138     return xmlSecGnuTLSX509CrlDup((gnutls_x509_crl_t)ptr);
139 }
140 
141 static void
xmlSecGnuTLSX509CrlListDestroyItem(xmlSecPtr ptr)142 xmlSecGnuTLSX509CrlListDestroyItem(xmlSecPtr ptr) {
143     xmlSecAssert(ptr != NULL);
144 
145     gnutls_x509_crl_deinit((gnutls_x509_crl_t)ptr);
146 }
147 
148 static void
xmlSecGnuTLSX509CrlListDebugDumpItem(xmlSecPtr ptr,FILE * output)149 xmlSecGnuTLSX509CrlListDebugDumpItem(xmlSecPtr ptr, FILE* output) {
150     xmlSecAssert(ptr != NULL);
151     xmlSecAssert(output != NULL);
152 
153     xmlSecGnuTLSX509CrlDebugDump((gnutls_x509_crl_t)ptr, output);
154 }
155 
156 
157 static void
xmlSecGnuTLSX509CrlListDebugXmlDumpItem(xmlSecPtr ptr,FILE * output)158 xmlSecGnuTLSX509CrlListDebugXmlDumpItem(xmlSecPtr ptr, FILE* output) {
159     xmlSecAssert(ptr != NULL);
160     xmlSecAssert(output != NULL);
161 
162     xmlSecGnuTLSX509CrlDebugXmlDump((gnutls_x509_crl_t)ptr, output);
163 }
164 
165 /*************************************************************************
166  *
167  * x509 certs utils/helpers
168  *
169  ************************************************************************/
170 
171 /* HACK: gnutls doesn't have cert duplicate function, so we simply
172  write cert out and then read it back */
173 gnutls_x509_crt_t
xmlSecGnuTLSX509CertDup(gnutls_x509_crt_t src)174 xmlSecGnuTLSX509CertDup(gnutls_x509_crt_t src) {
175     xmlChar * buf = NULL;
176     gnutls_x509_crt_t res = NULL;
177 
178     xmlSecAssert2(src != NULL, NULL);
179 
180     buf = xmlSecGnuTLSX509CertBase64DerWrite(src, 0);
181     if(buf == NULL) {
182         xmlSecInternalError("xmlSecGnuTLSX509CertBase64DerWrite", NULL);
183         return (NULL);
184     }
185 
186     res = xmlSecGnuTLSX509CertBase64DerRead(buf);
187     if(res == NULL) {
188         xmlSecInternalError("xmlSecGnuTLSX509CertBase64DerRead", NULL);
189         xmlFree(buf);
190         return (NULL);
191     }
192 
193     /* done */
194     xmlFree(buf);
195     return (res);
196 }
197 
198 xmlChar *
xmlSecGnuTLSX509CertGetSubjectDN(gnutls_x509_crt_t cert)199 xmlSecGnuTLSX509CertGetSubjectDN(gnutls_x509_crt_t cert) {
200     char* buf = NULL;
201     size_t bufSize = 0;
202     int err;
203 
204     xmlSecAssert2(cert != NULL, NULL);
205 
206     /* get subject size */
207     err = gnutls_x509_crt_get_dn(cert, NULL, &bufSize);
208     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
209         xmlSecGnuTLSError("gnutls_x509_crt_get_dn", err, NULL);
210         return(NULL);
211     }
212 
213     /* allocate buffer */
214     buf = (char *)xmlMalloc(bufSize + 1);
215     if(buf == NULL) {
216         xmlSecMallocError(bufSize + 1, NULL);
217         return(NULL);
218     }
219 
220     /* finally write it out */
221     err = gnutls_x509_crt_get_dn(cert, buf, &bufSize);
222     if(err != GNUTLS_E_SUCCESS) {
223         xmlSecGnuTLSError("gnutls_x509_crt_get_dn", err, NULL);
224         xmlFree(buf);
225         return(NULL);
226     }
227 
228     /* done */
229     return(BAD_CAST buf);
230 }
231 
232 xmlChar *
xmlSecGnuTLSX509CertGetIssuerDN(gnutls_x509_crt_t cert)233 xmlSecGnuTLSX509CertGetIssuerDN(gnutls_x509_crt_t cert) {
234     char* buf = NULL;
235     size_t bufSize = 0;
236     int err;
237 
238     xmlSecAssert2(cert != NULL, NULL);
239 
240     /* get issuer size */
241     err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &bufSize);
242     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
243         xmlSecGnuTLSError("gnutls_x509_crt_get_issuer_dn", err, NULL);
244         return(NULL);
245     }
246 
247     /* allocate buffer */
248     buf = (char *)xmlMalloc(bufSize + 1);
249     if(buf == NULL) {
250         xmlSecMallocError(bufSize + 1, NULL);
251         return(NULL);
252     }
253 
254     /* finally write it out */
255     err = gnutls_x509_crt_get_issuer_dn(cert, buf, &bufSize);
256     if(err != GNUTLS_E_SUCCESS) {
257         xmlSecGnuTLSError("gnutls_x509_crt_get_issuer_dn", err, NULL);
258         xmlFree(buf);
259         return(NULL);
260     }
261 
262     /* done */
263     return(BAD_CAST buf);
264 }
265 
266 xmlChar *
xmlSecGnuTLSX509CertGetIssuerSerial(gnutls_x509_crt_t cert)267 xmlSecGnuTLSX509CertGetIssuerSerial(gnutls_x509_crt_t cert) {
268     xmlChar * res = NULL;
269     unsigned char* buf = NULL;
270     size_t bufSize = 0;
271     int err;
272 
273     xmlSecAssert2(cert != NULL, NULL);
274 
275     /* get issuer serial size */
276     err = gnutls_x509_crt_get_serial(cert, NULL, &bufSize);
277     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
278         xmlSecGnuTLSError("gnutls_x509_crt_get_serial", err, NULL);
279         return(NULL);
280     }
281 
282     /* allocate buffer */
283     buf = (unsigned char *)xmlMalloc(bufSize + 1);
284     if(buf == NULL) {
285         xmlSecMallocError(bufSize + 1, NULL);
286         return(NULL);
287     }
288 
289     /* write it out */
290     err = gnutls_x509_crt_get_serial(cert, buf, &bufSize);
291     if(err != GNUTLS_E_SUCCESS) {
292         xmlSecGnuTLSError("gnutls_x509_crt_get_serial", err, NULL);
293         xmlFree(buf);
294         return(NULL);
295     }
296 
297     /* convert to string */
298     res = xmlSecGnuTLSASN1IntegerWrite(buf, bufSize);
299     if(res == NULL) {
300         xmlSecInternalError("xmlSecGnuTLSASN1IntegerWrite", NULL);
301         xmlFree(buf);
302         return(NULL);
303     }
304 
305     /* done */
306     xmlFree(buf);
307     return(res);
308 }
309 
310 xmlChar *
xmlSecGnuTLSX509CertGetSKI(gnutls_x509_crt_t cert)311 xmlSecGnuTLSX509CertGetSKI(gnutls_x509_crt_t cert) {
312     xmlChar * res = NULL;
313     xmlSecByte* buf = NULL;
314     size_t bufSize = 0;
315     unsigned int critical = 0;
316     int err;
317 
318     xmlSecAssert2(cert != NULL, NULL);
319 
320     /* get ski size */
321     err = gnutls_x509_crt_get_subject_key_id(cert, NULL, &bufSize, &critical);
322     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
323         xmlSecGnuTLSError("gnutls_x509_crt_get_subject_key_id", err, NULL);
324         return(NULL);
325     }
326 
327     /* allocate buffer */
328     buf = (xmlSecByte *)xmlMalloc(bufSize + 1);
329     if(buf == NULL) {
330         xmlSecMallocError(bufSize + 1, NULL);
331         return(NULL);
332     }
333 
334     /* write it out */
335     err = gnutls_x509_crt_get_subject_key_id(cert, buf, &bufSize, &critical);
336     if(err != GNUTLS_E_SUCCESS) {
337         xmlSecGnuTLSError("gnutls_x509_crt_get_subject_key_id", err, NULL);
338         xmlFree(buf);
339         return(NULL);
340     }
341 
342     /* convert to string */
343     res = xmlSecBase64Encode(buf, bufSize, 0);
344     if(res == NULL) {
345         xmlSecInternalError("xmlSecBase64Encode", NULL);
346         xmlFree(buf);
347         return(NULL);
348     }
349 
350     /* done */
351     xmlFree(buf);
352     return(res);
353 }
354 
355 
356 gnutls_x509_crt_t
xmlSecGnuTLSX509CertBase64DerRead(xmlChar * buf)357 xmlSecGnuTLSX509CertBase64DerRead(xmlChar* buf) {
358     int ret;
359 
360     xmlSecAssert2(buf != NULL, NULL);
361 
362     /* usual trick with base64 decoding "in-place" */
363     ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf));
364     if(ret < 0) {
365         xmlSecInternalError("xmlSecBase64Decode", NULL);
366         return(NULL);
367     }
368 
369     return(xmlSecGnuTLSX509CertRead((const xmlSecByte*)buf, ret, xmlSecKeyDataFormatCertDer));
370 }
371 
372 gnutls_x509_crt_t
xmlSecGnuTLSX509CertRead(const xmlSecByte * buf,xmlSecSize size,xmlSecKeyDataFormat format)373 xmlSecGnuTLSX509CertRead(const xmlSecByte* buf, xmlSecSize size, xmlSecKeyDataFormat format) {
374     gnutls_x509_crt_t cert = NULL;
375     gnutls_x509_crt_fmt_t fmt;
376     gnutls_datum_t data;
377     int err;
378 
379     xmlSecAssert2(buf != NULL, NULL);
380     xmlSecAssert2(size > 0, NULL);
381 
382     /* figure out format */
383     switch(format) {
384     case xmlSecKeyDataFormatPem:
385     case xmlSecKeyDataFormatCertPem:
386         fmt = GNUTLS_X509_FMT_PEM;
387         break;
388     case xmlSecKeyDataFormatDer:
389     case xmlSecKeyDataFormatCertDer:
390         fmt = GNUTLS_X509_FMT_DER;
391         break;
392     default:
393         xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL,
394                          "format=%d", (int)format);
395         return(NULL);
396     }
397 
398     /* read cert */
399     err = gnutls_x509_crt_init(&cert);
400     if(err != GNUTLS_E_SUCCESS) {
401         xmlSecGnuTLSError("gnutls_x509_crt_init", err, NULL);
402         return(NULL);
403     }
404 
405     data.data = (unsigned char*)buf;
406     data.size = size;
407     err = gnutls_x509_crt_import(cert, &data, fmt);
408     if(err != GNUTLS_E_SUCCESS) {
409         xmlSecGnuTLSError("gnutls_x509_crt_import", err, NULL);
410         gnutls_x509_crt_deinit(cert);
411         return(NULL);
412     }
413 
414     return(cert);
415 }
416 
417 xmlChar*
xmlSecGnuTLSX509CertBase64DerWrite(gnutls_x509_crt_t cert,int base64LineWrap)418 xmlSecGnuTLSX509CertBase64DerWrite(gnutls_x509_crt_t cert, int base64LineWrap) {
419     xmlChar * res = NULL;
420     xmlSecByte* buf = NULL;
421     size_t bufSize = 0;
422     int err;
423 
424     xmlSecAssert2(cert != NULL, NULL);
425 
426     /* get size */
427     err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, NULL, &bufSize);
428     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
429         xmlSecGnuTLSError("gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)", err, NULL);
430         return(NULL);
431     }
432 
433     /* allocate buffer */
434     buf = (xmlSecByte *)xmlMalloc(bufSize + 1);
435     if(buf == NULL) {
436         xmlSecMallocError(bufSize + 1, NULL);
437         return(NULL);
438     }
439 
440     /* write it out */
441     err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, buf, &bufSize);
442     if(err != GNUTLS_E_SUCCESS) {
443         xmlSecGnuTLSError("gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)", err, NULL);
444         xmlFree(buf);
445         return(NULL);
446     }
447 
448     /* convert to string */
449     res = xmlSecBase64Encode(buf, bufSize, base64LineWrap);
450     if(res == NULL) {
451         xmlSecInternalError("xmlSecBase64Encode", NULL);
452         xmlFree(buf);
453         return(NULL);
454     }
455 
456     /* done */
457     xmlFree(buf);
458     return(res);
459 }
460 
461 void
xmlSecGnuTLSX509CertDebugDump(gnutls_x509_crt_t cert,FILE * output)462 xmlSecGnuTLSX509CertDebugDump(gnutls_x509_crt_t cert, FILE* output) {
463     xmlChar * buf;
464 
465     xmlSecAssert(cert != NULL);
466     xmlSecAssert(output != NULL);
467 
468     buf = xmlSecGnuTLSX509CertGetSubjectDN(cert);
469     if(buf != NULL) {
470         fprintf(output, "==== Subject Name: %s\n", buf);
471         xmlFree(buf);
472     } else {
473         fprintf(output, "==== Subject Name: unknown\n");
474     }
475 
476     buf = xmlSecGnuTLSX509CertGetIssuerDN(cert);
477     if(buf != NULL) {
478         fprintf(output, "==== Issuer Name: %s\n", buf);
479         xmlFree(buf);
480     } else {
481         fprintf(output, "==== Issuer Name: unknown\n");
482     }
483 
484     buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
485     if(buf != NULL) {
486         fprintf(output, "==== Issuer Serial: %s\n", buf);
487         xmlFree(buf);
488     } else {
489         fprintf(output, "==== Issuer Serial: unknown\n");
490     }
491 }
492 
493 void
xmlSecGnuTLSX509CertDebugXmlDump(gnutls_x509_crt_t cert,FILE * output)494 xmlSecGnuTLSX509CertDebugXmlDump(gnutls_x509_crt_t cert, FILE* output) {
495     xmlChar * buf;
496 
497     xmlSecAssert(cert != NULL);
498     xmlSecAssert(output != NULL);
499 
500     buf = xmlSecGnuTLSX509CertGetSubjectDN(cert);
501     if(buf != NULL) {
502         fprintf(output, "<SubjectName>%s</SubjectName>\n", buf);
503         xmlFree(buf);
504     } else {
505         fprintf(output, "<SubjectName>unknown</SubjectName>\n");
506     }
507 
508     buf = xmlSecGnuTLSX509CertGetIssuerDN(cert);
509     if(buf != NULL) {
510         fprintf(output, "<IssuerName>%s</IssuerName>\n", buf);
511         xmlFree(buf);
512     } else {
513         fprintf(output, "<IssuerName>unknown</IssuerName>\n");
514     }
515 
516     buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
517     if(buf != NULL) {
518         fprintf(output, "<SerialNumber>%s</SerialNumber>\n", buf);
519         xmlFree(buf);
520     } else {
521         fprintf(output, "<SerialNumber>unknown</SerialNumber>\n");
522     }
523 }
524 
525 /*************************************************************************
526  *
527  * x509 crls utils/helpers
528  *
529  ************************************************************************/
530 
531 /* HACK: gnutls doesn't have crl duplicate function, so we simply
532  write crl out and then read it back */
533 gnutls_x509_crl_t
xmlSecGnuTLSX509CrlDup(gnutls_x509_crl_t src)534 xmlSecGnuTLSX509CrlDup(gnutls_x509_crl_t src) {
535     xmlChar * buf = NULL;
536     gnutls_x509_crl_t res = NULL;
537 
538     xmlSecAssert2(src != NULL, NULL);
539 
540     buf = xmlSecGnuTLSX509CrlBase64DerWrite(src, 0);
541     if(buf == NULL) {
542         xmlSecInternalError("xmlSecGnuTLSX509CrlBase64DerWrite", NULL);
543         return (NULL);
544     }
545 
546     res = xmlSecGnuTLSX509CrlBase64DerRead(buf);
547     if(res == NULL) {
548         xmlSecInternalError("xmlSecGnuTLSX509CrlBase64DerRead", NULL);
549         xmlFree(buf);
550         return (NULL);
551     }
552 
553     /* done */
554     xmlFree(buf);
555     return (res);
556 }
557 
558 xmlChar *
xmlSecGnuTLSX509CrlGetIssuerDN(gnutls_x509_crl_t crl)559 xmlSecGnuTLSX509CrlGetIssuerDN(gnutls_x509_crl_t crl) {
560     char* buf = NULL;
561     size_t bufSize = 0;
562     int err;
563 
564     xmlSecAssert2(crl != NULL, NULL);
565 
566     /* get issuer size */
567     err = gnutls_x509_crl_get_issuer_dn(crl, NULL, &bufSize);
568     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
569         xmlSecGnuTLSError("gnutls_x509_crl_get_issuer_dn", err, NULL);
570         return(NULL);
571     }
572 
573     /* allocate buffer */
574     buf = (char *)xmlMalloc(bufSize + 1);
575     if(buf == NULL) {
576         xmlSecMallocError(bufSize + 1, NULL);
577         return(NULL);
578     }
579 
580     /* finally write it out */
581     err = gnutls_x509_crl_get_issuer_dn(crl, buf, &bufSize);
582     if(err != GNUTLS_E_SUCCESS) {
583         xmlSecGnuTLSError("gnutls_x509_crl_get_issuer_dn", err, NULL);
584         xmlFree(buf);
585         return(NULL);
586     }
587 
588     /* done */
589     return(BAD_CAST buf);
590 }
591 
592 gnutls_x509_crl_t
xmlSecGnuTLSX509CrlBase64DerRead(xmlChar * buf)593 xmlSecGnuTLSX509CrlBase64DerRead(xmlChar* buf) {
594     int ret;
595 
596     xmlSecAssert2(buf != NULL, NULL);
597 
598     /* usual trick with base64 decoding "in-place" */
599     ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf));
600     if(ret < 0) {
601         xmlSecInternalError("xmlSecBase64Decode", NULL);
602         return(NULL);
603     }
604 
605     return(xmlSecGnuTLSX509CrlRead((const xmlSecByte*)buf, ret, xmlSecKeyDataFormatCertDer));
606 }
607 
608 gnutls_x509_crl_t
xmlSecGnuTLSX509CrlRead(const xmlSecByte * buf,xmlSecSize size,xmlSecKeyDataFormat format)609 xmlSecGnuTLSX509CrlRead(const xmlSecByte* buf, xmlSecSize size, xmlSecKeyDataFormat format) {
610     gnutls_x509_crl_t crl = NULL;
611     gnutls_x509_crt_fmt_t fmt;
612     gnutls_datum_t data;
613     int err;
614 
615     xmlSecAssert2(buf != NULL, NULL);
616     xmlSecAssert2(size > 0, NULL);
617 
618     /* figure out format */
619     switch(format) {
620     case xmlSecKeyDataFormatPem:
621     case xmlSecKeyDataFormatCertPem:
622         fmt = GNUTLS_X509_FMT_PEM;
623         break;
624     case xmlSecKeyDataFormatDer:
625     case xmlSecKeyDataFormatCertDer:
626         fmt = GNUTLS_X509_FMT_DER;
627         break;
628     default:
629         xmlSecOtherError2(XMLSEC_ERRORS_R_INVALID_FORMAT, NULL,
630                          "format=%d", (int)format);
631         return(NULL);
632     }
633 
634     /* read crl */
635     err = gnutls_x509_crl_init(&crl);
636     if(err != GNUTLS_E_SUCCESS) {
637         xmlSecGnuTLSError("gnutls_x509_crl_init", err, NULL);
638         return(NULL);
639     }
640 
641     data.data = (unsigned char*)buf;
642     data.size = size;
643     err = gnutls_x509_crl_import(crl, &data, fmt);
644     if(err != GNUTLS_E_SUCCESS) {
645         xmlSecGnuTLSError("gnutls_x509_crl_import", err, NULL);
646         gnutls_x509_crl_deinit(crl);
647         return(NULL);
648     }
649 
650     return(crl);
651 }
652 
653 xmlChar*
xmlSecGnuTLSX509CrlBase64DerWrite(gnutls_x509_crl_t crl,int base64LineWrap)654 xmlSecGnuTLSX509CrlBase64DerWrite(gnutls_x509_crl_t crl, int base64LineWrap) {
655     xmlChar * res = NULL;
656     xmlSecByte* buf = NULL;
657     size_t bufSize = 0;
658     int err;
659 
660     xmlSecAssert2(crl != NULL, NULL);
661 
662     /* get size */
663     err = gnutls_x509_crl_export(crl, GNUTLS_X509_FMT_DER, NULL, &bufSize);
664     if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
665         xmlSecGnuTLSError("gnutls_x509_crl_export(GNUTLS_X509_FMT_DER)", err, NULL);
666         return(NULL);
667     }
668 
669     /* allocate buffer */
670     buf = (xmlSecByte *)xmlMalloc(bufSize + 1);
671     if(buf == NULL) {
672         xmlSecMallocError(bufSize + 1, NULL);
673         return(NULL);
674     }
675 
676     /* write it out */
677     err = gnutls_x509_crl_export(crl, GNUTLS_X509_FMT_DER, buf, &bufSize);
678     if(err != GNUTLS_E_SUCCESS) {
679         xmlSecGnuTLSError("gnutls_x509_crl_export(GNUTLS_X509_FMT_DER)", err, NULL);
680         xmlFree(buf);
681         return(NULL);
682     }
683 
684     /* convert to string */
685     res = xmlSecBase64Encode(buf, bufSize, base64LineWrap);
686     if(res == NULL) {
687         xmlSecInternalError("xmlSecBase64Encode", NULL);
688         xmlFree(buf);
689         return(NULL);
690     }
691 
692     /* done */
693     xmlFree(buf);
694     return(res);
695 }
696 
697 void
xmlSecGnuTLSX509CrlDebugDump(gnutls_x509_crl_t crl,FILE * output)698 xmlSecGnuTLSX509CrlDebugDump(gnutls_x509_crl_t crl, FILE* output) {
699     xmlChar * buf;
700 
701     xmlSecAssert(crl != NULL);
702     xmlSecAssert(output != NULL);
703 
704     buf = xmlSecGnuTLSX509CrlGetIssuerDN(crl);
705     if(buf != NULL) {
706         fprintf(output, "==== Issuer Name: %s\n", buf);
707         xmlFree(buf);
708     } else {
709         fprintf(output, "==== Issuer Name: unknown\n");
710     }
711 }
712 
713 void
xmlSecGnuTLSX509CrlDebugXmlDump(gnutls_x509_crl_t crl,FILE * output)714 xmlSecGnuTLSX509CrlDebugXmlDump(gnutls_x509_crl_t crl, FILE* output) {
715     xmlChar * buf;
716 
717     xmlSecAssert(crl != NULL);
718     xmlSecAssert(output != NULL);
719 
720     buf = xmlSecGnuTLSX509CrlGetIssuerDN(crl);
721     if(buf != NULL) {
722         fprintf(output, "<IssuerName>%s</IssuerName>\n", buf);
723         xmlFree(buf);
724     } else {
725         fprintf(output, "<IssuerName>unknown</IssuerName>\n");
726     }
727 }
728 
729 /*************************************************************************
730  *
731  * Misc. utils/helpers
732  *
733  ************************************************************************/
734 xmlChar*
xmlSecGnuTLSASN1IntegerWrite(const unsigned char * data,size_t len)735 xmlSecGnuTLSASN1IntegerWrite(const unsigned char * data, size_t len) {
736     xmlChar *res = NULL;
737     int resLen = 64; /* not more than 64 chars */
738     unsigned long long int val = 0;
739     size_t ii = 0;
740     int shift = 0;
741     int ret;
742 
743     xmlSecAssert2(data != NULL, NULL);
744     xmlSecAssert2(len <= 9, NULL);
745 
746     /* HACK : to be fixed after GnuTLS provides a way to read opaque ASN1 integer */
747     for(ii = len; ii > 0; --ii, shift += 8) {
748         val |= ((unsigned long long)data[ii - 1]) << shift;
749     }
750 
751     res = (xmlChar*)xmlMalloc(resLen + 1);
752     if(res == NULL) {
753         xmlSecMallocError(resLen + 1, NULL);
754         return(NULL);
755     }
756 
757     ret = xmlStrPrintf(res, resLen, "%llu", val);
758     if(ret < 0) {
759         xmlSecXmlError("xmlStrPrintf", NULL);
760         xmlFree(res);
761         return(NULL);
762     }
763 
764     return(res);
765 }
766 
767 /*************************************************************************
768  *
769  * pkcs12 utils/helpers
770  *
771  ************************************************************************/
772 int
xmlSecGnuTLSPkcs12LoadMemory(const xmlSecByte * data,xmlSecSize dataSize,const char * pwd,gnutls_x509_privkey_t * priv_key,gnutls_x509_crt_t * key_cert,xmlSecPtrListPtr certsList)773 xmlSecGnuTLSPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
774                              const char *pwd,
775                              gnutls_x509_privkey_t * priv_key,
776                              gnutls_x509_crt_t * key_cert,
777                              xmlSecPtrListPtr certsList)
778 {
779     gnutls_pkcs12_t pkcs12 = NULL;
780     gnutls_pkcs12_bag_t bag = NULL;
781     gnutls_x509_crt_t cert = NULL;
782     gnutls_datum_t datum;
783     xmlSecSize certsSize;
784     int res = -1;
785     int idx;
786     int err;
787     int ret;
788 
789     xmlSecAssert2(data != NULL, -1);
790     xmlSecAssert2(dataSize > 0, -1);
791     xmlSecAssert2(priv_key != NULL, -1);
792     xmlSecAssert2((*priv_key) == NULL, -1);
793     xmlSecAssert2(key_cert!= NULL, -1);
794     xmlSecAssert2((*key_cert) == NULL, -1);
795     xmlSecAssert2(certsList != NULL, -1);
796 
797     /* read pkcs12 in internal structure */
798     err = gnutls_pkcs12_init(&pkcs12);
799     if(err != GNUTLS_E_SUCCESS) {
800         xmlSecGnuTLSError("gnutls_pkcs12_init", err, NULL);
801         goto done;
802     }
803 
804     datum.data = (unsigned char *)data;
805     datum.size = dataSize;
806     err = gnutls_pkcs12_import(pkcs12, &datum, GNUTLS_X509_FMT_DER, 0);
807     if(err != GNUTLS_E_SUCCESS) {
808         xmlSecGnuTLSError("gnutls_pkcs12_import", err, NULL);
809         goto done;
810     }
811 
812     /* verify */
813     err = gnutls_pkcs12_verify_mac(pkcs12, pwd);
814     if(err != GNUTLS_E_SUCCESS) {
815         xmlSecGnuTLSError("gnutls_pkcs12_verify_mac", err, NULL);
816         goto done;
817     }
818 
819     /* scan the pkcs structure and find the first private key */
820     for(idx = 0; ; ++idx) {
821         int bag_type;
822         int elements_in_bag;
823         int ii;
824 
825         err = gnutls_pkcs12_bag_init(&bag);
826         if(err != GNUTLS_E_SUCCESS) {
827             xmlSecGnuTLSError("gnutls_pkcs12_bag_init", err, NULL);
828             goto done;
829         }
830 
831         err = gnutls_pkcs12_get_bag(pkcs12, idx, bag);
832         if(err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
833             /* scanned the whole pkcs12, stop */
834             break;
835         } else if(err != GNUTLS_E_SUCCESS) {
836             xmlSecGnuTLSError("gnutls_pkcs12_get_bag", err, NULL);
837             goto done;
838         }
839 
840         /* check if we need to decrypt the bag */
841         bag_type = gnutls_pkcs12_bag_get_type(bag, 0);
842         if(bag_type < 0) {
843             xmlSecGnuTLSError("gnutls_pkcs12_bag_get_type", bag_type, NULL);
844             goto done;
845         }
846         if(bag_type == GNUTLS_BAG_ENCRYPTED) {
847             err = gnutls_pkcs12_bag_decrypt(bag, pwd);
848             if(err != GNUTLS_E_SUCCESS) {
849                 xmlSecGnuTLSError("gnutls_pkcs12_bag_decrypt", err, NULL);
850                 goto done;
851             }
852         }
853 
854         /* scan elements in bag */
855         elements_in_bag = gnutls_pkcs12_bag_get_count(bag);
856         if(elements_in_bag < 0) {
857             xmlSecGnuTLSError("gnutls_pkcs12_bag_get_count", elements_in_bag, NULL);
858             goto done;
859         }
860         for(ii = 0; ii < elements_in_bag; ++ii) {
861             bag_type = gnutls_pkcs12_bag_get_type(bag, ii);
862             if(bag_type < 0) {
863                 xmlSecGnuTLSError("gnutls_pkcs12_bag_get_type", bag_type, NULL);
864                 goto done;
865             }
866 
867             err = gnutls_pkcs12_bag_get_data(bag, ii, &datum);
868             if(err != GNUTLS_E_SUCCESS) {
869                 xmlSecGnuTLSError("gnutls_pkcs12_bag_get_data", err, NULL);
870                 goto done;
871             }
872 
873             switch(bag_type) {
874             case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
875             case GNUTLS_BAG_PKCS8_KEY:
876                 /* we want only the first private key */
877                 if((*priv_key) == NULL) {
878                     err = gnutls_x509_privkey_init(priv_key);
879                     if(err != GNUTLS_E_SUCCESS) {
880                         xmlSecGnuTLSError("gnutls_x509_privkey_init", err, NULL);
881                         goto done;
882                     }
883 
884                     err = gnutls_x509_privkey_import_pkcs8((*priv_key),
885                                 &datum, GNUTLS_X509_FMT_DER,
886                                 pwd,
887                                 (bag_type == GNUTLS_BAG_PKCS8_KEY) ? GNUTLS_PKCS_PLAIN : 0);
888                     if(err != GNUTLS_E_SUCCESS) {
889                         xmlSecGnuTLSError("gnutls_x509_privkey_import_pkcs8", err, NULL);
890                         goto done;
891                     }
892                 }
893                 break;
894             case GNUTLS_BAG_CERTIFICATE:
895                 err = gnutls_x509_crt_init(&cert);
896                 if(err != GNUTLS_E_SUCCESS) {
897                     xmlSecGnuTLSError("gnutls_x509_crt_init", err, NULL);
898                     goto done;
899                 }
900 
901                 err = gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER);
902                 if(err != GNUTLS_E_SUCCESS) {
903                     xmlSecGnuTLSError("gnutls_x509_crt_import", err, NULL);
904                     goto done;
905                 }
906 
907                 ret = xmlSecPtrListAdd(certsList, cert);
908                 if(ret < 0) {
909                     xmlSecInternalError("xmlSecPtrListAdd(certsList)", NULL);
910                     goto done;
911                 }
912                 cert = NULL; /* owned by certsList now */
913                 break;
914             default:
915                 /* ignore unknown bag element */
916                 break;
917             }
918         }
919 
920         /* done with bag */
921         gnutls_pkcs12_bag_deinit(bag);
922         bag = NULL;
923     }
924 
925     /* check we have private key */
926     if((*priv_key) == NULL) {
927         xmlSecOtherError(XMLSEC_ERRORS_R_KEY_NOT_FOUND, NULL,
928                          "Private key was not found in pkcs12 object");
929         goto done;
930     }
931 
932     /* we will search for key cert using the key id */
933     certsSize = xmlSecPtrListGetSize(certsList);
934     if(certsSize > 0) {
935         size_t cert_id_size = 0;
936         size_t key_id_size = 0;
937         xmlSecByte cert_id[100];
938         xmlSecByte key_id[100];
939         xmlSecSize ii;
940 
941         key_id_size = sizeof(key_id);
942         err = gnutls_x509_privkey_get_key_id((*priv_key), 0, key_id, &key_id_size);
943         if(err != GNUTLS_E_SUCCESS) {
944             xmlSecGnuTLSError("gnutls_x509_privkey_get_key_id", err, NULL);
945             goto done;
946         }
947         for(ii = 0; ii < certsSize; ++ii) {
948             gnutls_x509_crt_t tmp;
949 
950             tmp = xmlSecPtrListGetItem(certsList, ii);
951             if(tmp == NULL) {
952                 continue;
953             }
954 
955             cert_id_size = sizeof(cert_id);
956             err = gnutls_x509_crt_get_key_id(tmp, 0, cert_id, &cert_id_size);
957             if(err != GNUTLS_E_SUCCESS) {
958                 xmlSecGnuTLSError("gnutls_x509_crt_get_key_id", err, NULL);
959                 goto done;
960             }
961 
962             /* if key ids match, then this is THE key cert!!! */
963             if((key_id_size == cert_id_size) && (memcmp(key_id, cert_id, key_id_size) == 0)) {
964                 (*key_cert) = xmlSecGnuTLSX509CertDup(tmp);
965                 if((*key_cert) == NULL) {
966                     xmlSecInternalError("xmlSecGnuTLSX509CertDup", NULL);
967                     goto done;
968                 }
969 
970                 break;
971             }
972         }
973 
974         /* check we have key cert */
975         if((*key_cert) == NULL) {
976             xmlSecOtherError(XMLSEC_ERRORS_R_CERT_NOT_FOUND, NULL,
977                              "Certificate for the private key was not found in pkcs12 object");
978             goto done;
979         }
980     }
981 
982 
983     /* success!!! */
984     res = 0;
985 
986 done:
987     if(cert != NULL) {
988         gnutls_x509_crt_deinit(cert);
989     }
990     if(bag != NULL) {
991         gnutls_pkcs12_bag_deinit(bag);
992     }
993     if(pkcs12 != NULL) {
994         gnutls_pkcs12_deinit(pkcs12);
995     }
996     return(res);
997 }
998 
999 xmlSecKeyDataPtr
xmlSecGnuTLSCreateKeyDataAndAdoptPrivKey(gnutls_x509_privkey_t priv_key)1000 xmlSecGnuTLSCreateKeyDataAndAdoptPrivKey(gnutls_x509_privkey_t priv_key) {
1001     xmlSecKeyDataPtr res = NULL;
1002     int key_alg;
1003     int ret;
1004 
1005     xmlSecAssert2(priv_key != NULL, NULL);
1006 
1007     /* create key value data */
1008     key_alg = gnutls_x509_privkey_get_pk_algorithm(priv_key);
1009     if(key_alg < 0) {
1010         xmlSecGnuTLSError("gnutls_x509_privkey_get_pk_algorithm", key_alg < 0, NULL);
1011         return (NULL);
1012     }
1013     switch(key_alg) {
1014 #ifndef XMLSEC_NO_RSA
1015     case GNUTLS_PK_RSA:
1016         res = xmlSecKeyDataCreate(xmlSecGnuTLSKeyDataRsaId);
1017         if(res == NULL) {
1018             xmlSecInternalError("xmlSecKeyDataCreate(KeyDataRsaId)", NULL);
1019             return(NULL);
1020         }
1021 
1022         ret = xmlSecGnuTLSKeyDataRsaAdoptPrivateKey(res, priv_key);
1023         if(ret < 0) {
1024             xmlSecInternalError("xmlSecGnuTLSKeyDataRsaAdoptPrivateKey(KeyDataRsaId)", NULL);
1025             xmlSecKeyDataDestroy(res);
1026             return(NULL);
1027         }
1028         break;
1029 #endif /* XMLSEC_NO_RSA */
1030 
1031 #ifndef XMLSEC_NO_DSA
1032     case GNUTLS_PK_DSA:
1033         res = xmlSecKeyDataCreate(xmlSecGnuTLSKeyDataDsaId);
1034         if(res == NULL) {
1035             xmlSecInternalError("xmlSecKeyDataCreate(KeyDataDsaId)", NULL);
1036             return(NULL);
1037         }
1038 
1039         ret = xmlSecGnuTLSKeyDataDsaAdoptPrivateKey(res, priv_key);
1040         if(ret < 0) {
1041             xmlSecInternalError("xmlSecGnuTLSKeyDataDsaAdoptPrivateKey(KeyDataDsaId)", NULL);
1042             xmlSecKeyDataDestroy(res);
1043             return(NULL);
1044         }
1045         break;
1046 #endif /* XMLSEC_NO_DSA */
1047     default:
1048         xmlSecInvalidIntegerTypeError("key_alg", key_alg, "supported algorithm", NULL);
1049         return(NULL);
1050     }
1051 
1052     /* done */
1053     return(res);
1054 }
1055 
1056 /*************************************************************************
1057  *
1058  * LDAP DN parser
1059  *
1060  ************************************************************************/
1061 void
xmlSecGnuTLSDnAttrsInitialize(xmlSecGnuTLSDnAttr * attrs,xmlSecSize attrsSize)1062 xmlSecGnuTLSDnAttrsInitialize(xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize) {
1063     xmlSecAssert(attrs != NULL);
1064     xmlSecAssert(attrsSize > 0);
1065 
1066     memset(attrs, 0, attrsSize * sizeof(xmlSecGnuTLSDnAttr));
1067 }
1068 
1069 void
xmlSecGnuTLSDnAttrsDeinitialize(xmlSecGnuTLSDnAttr * attrs,xmlSecSize attrsSize)1070 xmlSecGnuTLSDnAttrsDeinitialize(xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize) {
1071     xmlSecSize ii;
1072 
1073     xmlSecAssert(attrs != NULL);
1074     xmlSecAssert(attrsSize > 0);
1075 
1076     for(ii = 0; ii < attrsSize; ++ii) {
1077         if(attrs[ii].key != NULL) {
1078             xmlFree(attrs[ii].key);
1079         }
1080         if(attrs[ii].value != NULL) {
1081             xmlFree(attrs[ii].value);
1082         }
1083     }
1084     memset(attrs, 0, attrsSize * sizeof(xmlSecGnuTLSDnAttr));
1085 }
1086 
1087 const xmlSecGnuTLSDnAttr *
xmlSecGnuTLSDnAttrrsFind(const xmlSecGnuTLSDnAttr * attrs,xmlSecSize attrsSize,const xmlChar * key)1088 xmlSecGnuTLSDnAttrrsFind(const xmlSecGnuTLSDnAttr * attrs,
1089                          xmlSecSize attrsSize,
1090                          const xmlChar * key)
1091 {
1092     xmlSecSize ii;
1093 
1094     xmlSecAssert2(attrs != NULL, NULL);
1095     xmlSecAssert2(attrsSize > 0, NULL);
1096     xmlSecAssert2(key != NULL, NULL);
1097 
1098     for(ii = 0; ii < attrsSize; ++ii) {
1099         /* simple case */
1100         if(xmlStrcasecmp(key, attrs[ii].key) == 0) {
1101             return(&(attrs[ii]));
1102         }
1103 
1104         /* special case for emailAddress (as usual) */
1105         if((xmlStrcasecmp(key, BAD_CAST "emailAddress") == 0) &&
1106            (xmlStrcasecmp(attrs[ii].key, BAD_CAST "email") == 0))
1107         {
1108             return(&(attrs[ii]));
1109         }
1110         if((xmlStrcasecmp(key, BAD_CAST "email") == 0) &&
1111            (xmlStrcasecmp(attrs[ii].key, BAD_CAST "emailAddress") == 0))
1112         {
1113             return(&(attrs[ii]));
1114         }
1115     }
1116 
1117     /* not found :( */
1118     return(NULL);
1119 }
1120 
1121 int
xmlSecGnuTLSDnAttrsEqual(const xmlSecGnuTLSDnAttr * ll,xmlSecSize llSize,const xmlSecGnuTLSDnAttr * rr,xmlSecSize rrSize)1122 xmlSecGnuTLSDnAttrsEqual(const xmlSecGnuTLSDnAttr * ll, xmlSecSize llSize,
1123                          const xmlSecGnuTLSDnAttr * rr, xmlSecSize rrSize)
1124 {
1125     xmlSecSize llNum = 0;
1126     xmlSecSize rrNum = 0;
1127     const xmlSecGnuTLSDnAttr * tmp;
1128     xmlSecSize ii;
1129 
1130     xmlSecAssert2(ll != NULL, -1);
1131     xmlSecAssert2(llSize > 0, -1);
1132     xmlSecAssert2(rr != NULL, -1);
1133     xmlSecAssert2(rrSize > 0, -1);
1134 
1135     /* compare number of non-nullattributes */
1136     for(ii = 0; ii < llSize; ++ii) {
1137         if(ll[ii].key != NULL) {
1138             ++llNum;
1139         }
1140     }
1141     for(ii = 0; ii < rrSize; ++ii) {
1142         if(rr[ii].key != NULL) {
1143             ++rrNum;
1144         }
1145     }
1146     if(llNum != rrNum) {
1147         return(0);
1148     }
1149 
1150     /* make sure that all ll attrs are equal to rr attrs */
1151     for(ii = 0; ii < llSize; ++ii) {
1152         if(ll[ii].key == NULL) {
1153             continue;
1154         }
1155 
1156         tmp = xmlSecGnuTLSDnAttrrsFind(rr, rrSize, ll[ii].key);
1157         if(tmp == NULL) {
1158             return(0); /* attribute was not found */
1159         }
1160 
1161         if(!xmlStrEqual(ll[ii].value, tmp->value)) {
1162             return(0); /* different values */
1163         }
1164     }
1165 
1166     /* good!!! */
1167     return(1);
1168 }
1169 
1170 /*
1171 Distinguished name syntax
1172 
1173 The formal syntax for a Distinguished Name (DN) is based on RFC 2253.
1174 The Backus Naur Form (BNF) syntax is defined as follows:
1175 
1176     <name> ::= <name-component> ( <spaced-separator> )
1177           | <name-component> <spaced-separator> <name>
1178 
1179    <spaced-separator> ::= <optional-space>
1180                    <separator>
1181                    <optional-space>
1182 
1183    <separator> ::=  "," | ";"
1184 
1185    <optional-space> ::= ( <CR> ) *( " " )
1186 
1187    <name-component> ::= <attribute>
1188            | <attribute> <optional-space> "+"
1189              <optional-space> <name-component>
1190 
1191    <attribute> ::= <string>
1192            | <key> <optional-space> "=" <optional-space> <string>
1193 
1194    <key> ::= 1*( <keychar> ) | "OID." <oid> | "oid." <oid>
1195    <keychar> ::= letters, numbers, and space
1196 
1197    <oid> ::= <digitstring> | <digitstring> "." <oid>
1198    <digitstring> ::= 1*<digit>
1199    <digit> ::= digits 0-9
1200 
1201    <string> ::= *( <stringchar> | <pair> )
1202             | '"' *( <stringchar> | <special> | <pair> ) '"'
1203             | "#" <hex>
1204 
1205 
1206    <special> ::= "," | "=" | <CR> | "+" | "<" |  ">"
1207             | "#" | ";"
1208 
1209    <pair> ::= "\" ( <special> | "\" | '"')
1210    <stringchar> ::= any character except <special> or "\" or '"'
1211 
1212 
1213    <hex> ::= 2*<hexchar>
1214    <hexchar> ::= 0-9, a-f, A-F
1215 
1216 A semicolon (;) character can be used to separate RDNs in a distinguished name,
1217 although the comma (,) character is the typical notation.
1218 
1219 White-space characters (spaces) might be present on either side of the comma or
1220 semicolon. The white-space characters are ignored, and the semicolon is replaced
1221 with a comma.
1222 
1223 In addition, space (' ' ASCII 32) characters may be present either before or
1224 after a '+' or '='. These space characters are ignored when parsing.
1225 */
1226 enum xmlSecGnuTLSDnParseState {
1227     xmlSecGnuTLSDnParseState_BeforeNameComponent = 0,
1228     xmlSecGnuTLSDnParseState_Key,
1229     xmlSecGnuTLSDnParseState_BeforeString,
1230     xmlSecGnuTLSDnParseState_String,
1231     xmlSecGnuTLSDnParseState_QuotedString,
1232     xmlSecGnuTLSDnParseState_AfterQuotedString
1233 };
1234 
1235 #define XMLSEC_GNUTLS_IS_SPACE(ch)      \
1236         (((ch) == ' ') || ((ch) == '\n') || ((ch) == '\r'))
1237 
1238 int
xmlSecGnuTLSDnAttrsParse(const xmlChar * dn,xmlSecGnuTLSDnAttr * attrs,xmlSecSize attrsSize)1239 xmlSecGnuTLSDnAttrsParse(const xmlChar * dn,
1240                          xmlSecGnuTLSDnAttr * attrs, xmlSecSize attrsSize)
1241 {
1242     xmlChar * tmp = NULL;
1243     xmlChar * p;
1244     xmlChar ch;
1245     enum xmlSecGnuTLSDnParseState state;
1246     int slash;
1247     xmlSecSize pos;
1248     int res = -1;
1249 
1250     xmlSecAssert2(dn != NULL, -1);
1251     xmlSecAssert2(attrs != NULL, -1);
1252     xmlSecAssert2(attrsSize > 0, -1);
1253 
1254     /* allocate buffer, we don't need more than string */
1255     tmp = (xmlChar *)xmlMalloc(xmlStrlen(dn) + 1);
1256     if(tmp == NULL) {
1257         xmlSecMallocError(xmlStrlen(dn) + 1, NULL);
1258         goto done;
1259     }
1260 
1261     /* state machine */
1262     state = xmlSecGnuTLSDnParseState_BeforeNameComponent;
1263     slash = 0;
1264     pos = 0;
1265     p = tmp;
1266     for(ch = (*dn); ; ch = *(++dn)) {
1267         switch(state) {
1268         case xmlSecGnuTLSDnParseState_BeforeNameComponent:
1269             if(!XMLSEC_GNUTLS_IS_SPACE(ch)) {
1270                 *(p++) = ch; /* we are sure we have enough buffer */
1271                 state = xmlSecGnuTLSDnParseState_Key;
1272             } else {
1273                 /* just skip space */
1274             }
1275             break;
1276         case xmlSecGnuTLSDnParseState_Key:
1277             /* we don't support
1278             1) <attribute><optional-space>"+"<optional-space><name-component>
1279             2) <attribute> ::= <string>
1280             */
1281             if(ch != '=') {
1282                 *(p++) = ch; /* we are sure we have enough buffer */
1283             } else {
1284                 *(p) = '\0';
1285                 /* remove spaces back */
1286                 while((p > tmp) && (XMLSEC_GNUTLS_IS_SPACE(*(p - 1)))) {
1287                     *(--p) = '\0';
1288                 }
1289 
1290                 /* insert into the attrs */
1291                 if(pos >= attrsSize) {
1292                     xmlSecInvalidSizeLessThanError("Attributes",
1293                                                    attrsSize, pos, NULL);
1294                     goto done;
1295                 }
1296                 attrs[pos].key = xmlStrdup(tmp);
1297                 if(attrs[pos].key == NULL) {
1298                     xmlSecStrdupError(tmp, NULL);
1299                     goto done;
1300                 }
1301 
1302                 state = xmlSecGnuTLSDnParseState_BeforeString;
1303                 p = tmp;
1304             }
1305             break;
1306         case xmlSecGnuTLSDnParseState_BeforeString:
1307             if(!XMLSEC_GNUTLS_IS_SPACE(ch)) {
1308                 if(ch != '\"') {
1309                     state = xmlSecGnuTLSDnParseState_String;
1310                     slash = 0;
1311                     --dn; /* small hack, so we can look at the same char
1312                            again with the correct state */
1313                 } else {
1314                     state = xmlSecGnuTLSDnParseState_QuotedString;
1315                     slash = 0;
1316                 }
1317             } else {
1318                 /* just skip space */
1319             }
1320             break;
1321         case xmlSecGnuTLSDnParseState_String:
1322             if(slash == 1) {
1323                 *(p++) = ch; /* we are sure we have enough buffer */
1324                 slash = 0;
1325             } else if(ch == '\\') {
1326                 slash = 1;
1327             } else if((ch == ',') || (ch == ';') || (ch == '\0')) {
1328                 *(p) = '\0';
1329                 /* remove spaces back */
1330                 while((p > tmp) && (XMLSEC_GNUTLS_IS_SPACE(*(p - 1)))) {
1331                     *(--p) = '\0';
1332                 }
1333 
1334                 attrs[pos].value = xmlStrdup(tmp);
1335                 if(attrs[pos].value == NULL) {
1336                     xmlSecStrdupError(tmp, NULL);
1337                     goto done;
1338                 }
1339                 state = xmlSecGnuTLSDnParseState_BeforeNameComponent;
1340                 ++pos;
1341                 p = tmp;
1342             } else {
1343                 *(p++) = ch; /* we are sure we have enough buffer */
1344             }
1345             break;
1346         case xmlSecGnuTLSDnParseState_QuotedString:
1347             if(slash == 1) {
1348                 *(p++) = ch; /* we are sure we have enough buffer */
1349                 slash = 0;
1350             } else if(ch == '\\') {
1351                 slash = 1;
1352             } else if(ch == '\"') {
1353                 *(p) = '\0';
1354                 /* don't remove spaces for quoted string */
1355 
1356                 attrs[pos].value = xmlStrdup(tmp);
1357                 if(attrs[pos].value == NULL) {
1358                     xmlSecStrdupError(tmp, NULL);
1359                     goto done;
1360                 }
1361                 state = xmlSecGnuTLSDnParseState_AfterQuotedString;
1362                 ++pos;
1363                 p = tmp;
1364             } else {
1365                 *(p++) = ch; /* we are sure we have enough buffer */
1366             }
1367             break;
1368         case xmlSecGnuTLSDnParseState_AfterQuotedString:
1369             if(!XMLSEC_GNUTLS_IS_SPACE(ch)) {
1370                 if((ch == ',') || (ch == ';') || (ch == '\0')) {
1371                     state = xmlSecGnuTLSDnParseState_BeforeNameComponent;
1372                 } else {
1373                     xmlSecInvalidIntegerDataError("ch", ch, "space,',',';','\\0'", NULL);
1374                     goto done;
1375                 }
1376             } else {
1377                 /* just skip space */
1378             }
1379             break;
1380         }
1381 
1382         if(ch == '\0') {
1383             /* done */
1384             break;
1385         }
1386     }
1387 
1388     /* check end state */
1389     if(state != xmlSecGnuTLSDnParseState_BeforeNameComponent) {
1390         xmlSecInvalidIntegerDataError("state", state, "xmlSecGnuTLSDnParseState_BeforeNameComponent", NULL);
1391         goto done;
1392     }
1393 
1394     /* debug
1395     {
1396         xmlSecSize ii;
1397         for(ii = 0; ii < attrsSize; ++ii) {
1398             if(attrs[ii].key != NULL) {
1399                 printf("DEBUG: attrs - %s=>%s\n", attrs[ii].key, attrs[ii].value);
1400             }
1401         }
1402     }
1403     */
1404 
1405     /* done */
1406     res = 0;
1407 
1408 done:
1409     if(tmp != NULL) {
1410         xmlFree(tmp);
1411     }
1412     return(res);
1413 }
1414 
1415 
1416 #endif /* XMLSEC_NO_X509 */
1417 
1418 
1419 
1420