1 /*
2  * Copyright (C) 2003-2014 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  *
21  */
22 
23 #include "gnutls_int.h"
24 #include <libtasn1.h>
25 #include <datum.h>
26 #include <global.h>
27 #include "errors.h"
28 #include <str.h>
29 #include <common.h>
30 #include <num.h>
31 
32 /* This file includes all the required to parse an X.509 Distriguished
33  * Name (you need a parser just to read a name in the X.509 protocols!!!)
34  */
35 
append_elements(ASN1_TYPE asn1_struct,const char * asn1_rdn_name,gnutls_buffer_st * str,int k1,unsigned last)36 static int append_elements(ASN1_TYPE asn1_struct, const char *asn1_rdn_name, gnutls_buffer_st *str, int k1, unsigned last)
37 {
38 	int k2, result, max_k2;
39 	int len;
40 	uint8_t value[MAX_STRING_LEN];
41 	char tmpbuffer1[MAX_NAME_SIZE];
42 	char tmpbuffer2[MAX_NAME_SIZE];
43 	char tmpbuffer3[MAX_NAME_SIZE];
44 	const char *ldap_desc;
45 	char oid[MAX_OID_SIZE];
46 	gnutls_datum_t td = { NULL, 0 };
47 	gnutls_datum_t tvd = { NULL, 0 };
48 
49 	/* create a string like "tbsCertList.issuer.rdnSequence.?1"
50 	 */
51 	if (asn1_rdn_name[0] != 0)
52 		snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
53 			 asn1_rdn_name, k1);
54 	else
55 		snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
56 			 k1);
57 
58 	len = sizeof(value) - 1;
59 	result =
60 	    asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
61 
62 	if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { /* expected */
63 		gnutls_assert();
64 		result = _gnutls_asn2err(result);
65 		goto cleanup;
66 	}
67 
68 	k2 = 0;
69 
70 	result = asn1_number_of_elements(asn1_struct, tmpbuffer1, &max_k2);
71 	if (result != ASN1_SUCCESS) {
72 		gnutls_assert();
73 		result = _gnutls_asn2err(result);
74 		goto cleanup;
75 	}
76 
77 	do {		/* Move to the attribute type and values
78 				 */
79 		k2++;
80 
81 		if (tmpbuffer1[0] != 0)
82 			snprintf(tmpbuffer2, sizeof(tmpbuffer2),
83 				 "%s.?%u", tmpbuffer1, k2);
84 		else
85 			snprintf(tmpbuffer2, sizeof(tmpbuffer2),
86 				 "?%u", k2);
87 
88 		/* Try to read the RelativeDistinguishedName attributes.
89 		 */
90 
91 		len = sizeof(value) - 1;
92 		result =
93 		    asn1_read_value(asn1_struct, tmpbuffer2, value,
94 				    &len);
95 
96 		if (result == ASN1_ELEMENT_NOT_FOUND)
97 			break;
98 		if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { /* expected */
99 			gnutls_assert();
100 			result = _gnutls_asn2err(result);
101 			goto cleanup;
102 		}
103 
104 		/* Read the OID
105 		 */
106 		_gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
107 				tmpbuffer2);
108 		_gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
109 				".type");
110 
111 		len = sizeof(oid) - 1;
112 		result =
113 		    asn1_read_value(asn1_struct, tmpbuffer3, oid,
114 				    &len);
115 
116 		if (result == ASN1_ELEMENT_NOT_FOUND)
117 			break;
118 		else if (result != ASN1_SUCCESS) {
119 			gnutls_assert();
120 			result = _gnutls_asn2err(result);
121 			goto cleanup;
122 		}
123 
124 		/* Read the Value
125 		 */
126 		_gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
127 				tmpbuffer2);
128 		_gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
129 				".value");
130 
131 		len = 0;
132 
133 		result =
134 		    _gnutls_x509_read_value(asn1_struct,
135 					    tmpbuffer3, &tvd);
136 		if (result < 0) {
137 			gnutls_assert();
138 			goto cleanup;
139 		}
140 #define STR_APPEND(y) if ((result=_gnutls_buffer_append_str( str, y)) < 0) { \
141 	gnutls_assert(); \
142 	goto cleanup; \
143 }
144 #define DATA_APPEND(x,y) if ((result=_gnutls_buffer_append_data( str, x,y)) < 0) { \
145 	gnutls_assert(); \
146 	goto cleanup; \
147 }
148 		/*   The encodings of adjoining RelativeDistinguishedNames are separated
149 		 *   by a comma character (',' ASCII 44).
150 		 */
151 
152 		ldap_desc =
153 		    gnutls_x509_dn_oid_name(oid,
154 					    GNUTLS_X509_DN_OID_RETURN_OID);
155 
156 		STR_APPEND(ldap_desc);
157 		STR_APPEND("=");
158 
159 		result =
160 		    _gnutls_x509_dn_to_string(oid, tvd.data,
161 					      tvd.size, &td);
162 		if (result < 0) {
163 			gnutls_assert();
164 			_gnutls_debug_log
165 			    ("Cannot parse OID: '%s' with value '%s'\n",
166 			     oid, _gnutls_bin2hex(tvd.data,
167 						  tvd.size,
168 						  tmpbuffer3,
169 						  sizeof
170 						  (tmpbuffer3),
171 						  NULL));
172 			goto cleanup;
173 		}
174 
175 		DATA_APPEND(td.data, td.size);
176 		_gnutls_free_datum(&td);
177 		_gnutls_free_datum(&tvd);
178 
179 		/*   Where there is a multi-valued RDN, the outputs from adjoining
180 		 *   AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
181 		 *   character.
182 		 */
183 		if (k2 < max_k2) {
184 			STR_APPEND("+");
185 		} else if (!last) {
186 			STR_APPEND(",");
187 		}
188 	}
189 	while (1);
190 
191 	result = 0;
192 
193  cleanup:
194 	_gnutls_free_datum(&td);
195 	_gnutls_free_datum(&tvd);
196 	return result;
197 }
198 
199 int
_gnutls_x509_get_dn(ASN1_TYPE asn1_struct,const char * asn1_rdn_name,gnutls_datum_t * dn,unsigned flags)200 _gnutls_x509_get_dn(ASN1_TYPE asn1_struct,
201 		    const char *asn1_rdn_name, gnutls_datum_t * dn,
202 		    unsigned flags)
203 {
204 	gnutls_buffer_st out_str;
205 	int i, k1, result;
206 
207 	_gnutls_buffer_init(&out_str);
208 
209 	result = asn1_number_of_elements(asn1_struct, asn1_rdn_name, &k1);
210 	if (result != ASN1_SUCCESS) {
211 		if (result == ASN1_ELEMENT_NOT_FOUND || result == ASN1_VALUE_NOT_FOUND) {
212 			result = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
213 		} else {
214 			gnutls_assert();
215 			result = _gnutls_asn2err(result);
216 		}
217 		goto cleanup;
218 	}
219 
220 	if (k1 == 0) {
221 		gnutls_assert();
222 		result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
223 		goto cleanup;
224 	}
225 
226 	if (flags & GNUTLS_X509_DN_FLAG_COMPAT) {
227 		for (i=0;i<k1;i++) {
228 			result = append_elements(asn1_struct, asn1_rdn_name, &out_str, i+1, (i==(k1-1))?1:0);
229 			if (result < 0) {
230 				gnutls_assert();
231 				goto cleanup;
232 			}
233 		}
234 	} else {
235 		while (k1 > 0) {
236 			result = append_elements(asn1_struct, asn1_rdn_name, &out_str, k1, k1==1?1:0);
237 			if (result < 0) {
238 				gnutls_assert();
239 				goto cleanup;
240 			}
241 			k1--;
242 		}
243 	}
244 
245 	return _gnutls_buffer_to_datum(&out_str, dn, 1);
246 
247  cleanup:
248 	_gnutls_buffer_clear(&out_str);
249 	return result;
250 
251 }
252 
253 
254 /* Parses an X509 DN in the asn1_struct, and puts the output into
255  * the string buf. The output is an LDAP encoded DN.
256  *
257  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
258  * That is to point in the rndSequence.
259  */
260 int
_gnutls_x509_parse_dn(ASN1_TYPE asn1_struct,const char * asn1_rdn_name,char * buf,size_t * buf_size,unsigned flags)261 _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct,
262 		      const char *asn1_rdn_name, char *buf,
263 		      size_t * buf_size, unsigned flags)
264 {
265 	int ret;
266 	gnutls_datum_t dn = {NULL, 0};
267 
268 	if (buf_size == NULL) {
269 		gnutls_assert();
270 		return GNUTLS_E_INVALID_REQUEST;
271 	}
272 
273 	if (*buf_size > 0 && buf)
274 		buf[0] = 0;
275 	else
276 		*buf_size = 0;
277 
278 	ret = _gnutls_x509_get_dn(asn1_struct, asn1_rdn_name, &dn, flags);
279 	if (ret < 0)
280 		return gnutls_assert_val(ret);
281 
282 	if (dn.size >= (unsigned int) *buf_size) {
283 		gnutls_assert();
284 		*buf_size = dn.size + 1;
285 		ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
286 		goto cleanup;
287 	}
288 
289 	assert(dn.data != NULL);
290 
291 	if (buf) {
292 		memcpy(buf, dn.data, dn.size);
293 		buf[dn.size] = 0;
294 		*buf_size = dn.size;
295 	} else
296 		*buf_size = dn.size + 1;
297 
298 	ret = 0;
299       cleanup:
300 	_gnutls_free_datum(&dn);
301 	return ret;
302 }
303 
304 /* Parses an X509 DN in the asn1_struct, and searches for the
305  * given OID in the DN.
306  *
307  * If raw_flag == 0, the output will be encoded in the LDAP way. (#hex for non printable)
308  * Otherwise the raw DER data are returned.
309  *
310  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
311  * That is to point in the rndSequence.
312  *
313  * indx specifies which OID to return. Ie 0 means return the first specified
314  * OID found, 1 the second etc.
315  */
316 int
_gnutls_x509_parse_dn_oid(ASN1_TYPE asn1_struct,const char * asn1_rdn_name,const char * given_oid,int indx,unsigned int raw_flag,gnutls_datum_t * out)317 _gnutls_x509_parse_dn_oid(ASN1_TYPE asn1_struct,
318 			  const char *asn1_rdn_name,
319 			  const char *given_oid, int indx,
320 			  unsigned int raw_flag, gnutls_datum_t * out)
321 {
322 	int k2, k1, result;
323 	char tmpbuffer1[MAX_NAME_SIZE];
324 	char tmpbuffer2[MAX_NAME_SIZE];
325 	char tmpbuffer3[MAX_NAME_SIZE];
326 	gnutls_datum_t td;
327 	uint8_t value[256];
328 	char oid[MAX_OID_SIZE];
329 	int len;
330 	int i = 0;
331 
332 	k1 = 0;
333 	do {
334 
335 		k1++;
336 		/* create a string like "tbsCertList.issuer.rdnSequence.?1"
337 		 */
338 		if (asn1_rdn_name[0] != 0)
339 			snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
340 				 asn1_rdn_name, k1);
341 		else
342 			snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
343 				 k1);
344 
345 		len = sizeof(value) - 1;
346 		result =
347 		    asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
348 
349 		if (result == ASN1_ELEMENT_NOT_FOUND) {
350 			gnutls_assert();
351 			break;
352 		}
353 
354 		if (result != ASN1_VALUE_NOT_FOUND) {
355 			gnutls_assert();
356 			result = _gnutls_asn2err(result);
357 			goto cleanup;
358 		}
359 
360 		k2 = 0;
361 
362 		do {		/* Move to the attribute type and values
363 				 */
364 			k2++;
365 
366 			if (tmpbuffer1[0] != 0)
367 				snprintf(tmpbuffer2, sizeof(tmpbuffer2),
368 					 "%s.?%u", tmpbuffer1, k2);
369 			else
370 				snprintf(tmpbuffer2, sizeof(tmpbuffer2),
371 					 "?%u", k2);
372 
373 			/* Try to read the RelativeDistinguishedName attributes.
374 			 */
375 
376 			len = sizeof(value) - 1;
377 			result =
378 			    asn1_read_value(asn1_struct, tmpbuffer2, value,
379 					    &len);
380 
381 			if (result == ASN1_ELEMENT_NOT_FOUND) {
382 				break;
383 			}
384 			if (result != ASN1_VALUE_NOT_FOUND) {
385 				gnutls_assert();
386 				result = _gnutls_asn2err(result);
387 				goto cleanup;
388 			}
389 
390 			/* Read the OID
391 			 */
392 			_gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
393 					tmpbuffer2);
394 			_gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
395 					".type");
396 
397 			len = sizeof(oid) - 1;
398 			result =
399 			    asn1_read_value(asn1_struct, tmpbuffer3, oid,
400 					    &len);
401 
402 			if (result == ASN1_ELEMENT_NOT_FOUND)
403 				break;
404 			else if (result != ASN1_SUCCESS) {
405 				gnutls_assert();
406 				result = _gnutls_asn2err(result);
407 				goto cleanup;
408 			}
409 
410 			if (strcmp(oid, given_oid) == 0 && indx == i++) {	/* Found the OID */
411 
412 				/* Read the Value
413 				 */
414 				_gnutls_str_cpy(tmpbuffer3,
415 						sizeof(tmpbuffer3),
416 						tmpbuffer2);
417 				_gnutls_str_cat(tmpbuffer3,
418 						sizeof(tmpbuffer3),
419 						".value");
420 
421 				result =
422 				    _gnutls_x509_read_value(asn1_struct,
423 							    tmpbuffer3,
424 							    &td);
425 				if (result < 0) {
426 					gnutls_assert();
427 					goto cleanup;
428 				}
429 
430 				if (raw_flag != 0) {
431 					out->data = td.data;
432 					out->size = td.size;
433 					return 0;
434 
435 				} else {	/* parse data. raw_flag == 0 */
436 					result =
437 					    _gnutls_x509_dn_to_string(oid,
438 								      td.
439 								      data,
440 								      td.
441 								      size,
442 								      out);
443 
444 					_gnutls_free_datum(&td);
445 					if (result < 0) {
446 						gnutls_assert();
447 						goto cleanup;
448 					}
449 
450 					return 0;
451 
452 				}	/* raw_flag == 0 */
453 			}
454 		}
455 		while (1);
456 
457 	}
458 	while (1);
459 
460 	gnutls_assert();
461 
462 	result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
463 
464       cleanup:
465 	return result;
466 }
467 
468 
469 /* Parses an X509 DN in the asn1_struct, and returns the requested
470  * DN OID.
471  *
472  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
473  * That is to point in the rndSequence.
474  *
475  * indx specifies which OID to return. Ie 0 means return the first specified
476  * OID found, 1 the second etc.
477  */
478 int
_gnutls_x509_get_dn_oid(ASN1_TYPE asn1_struct,const char * asn1_rdn_name,int indx,void * _oid,size_t * sizeof_oid)479 _gnutls_x509_get_dn_oid(ASN1_TYPE asn1_struct,
480 			const char *asn1_rdn_name,
481 			int indx, void *_oid, size_t * sizeof_oid)
482 {
483 	int k2, k1, result;
484 	char tmpbuffer1[MAX_NAME_SIZE];
485 	char tmpbuffer2[MAX_NAME_SIZE];
486 	char tmpbuffer3[MAX_NAME_SIZE];
487 	char value[256];
488 	char oid[MAX_OID_SIZE];
489 	int len;
490 	int i = 0;
491 
492 	k1 = 0;
493 	do {
494 
495 		k1++;
496 		/* create a string like "tbsCertList.issuer.rdnSequence.?1"
497 		 */
498 		if (asn1_rdn_name[0] != 0)
499 			snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
500 				 asn1_rdn_name, k1);
501 		else
502 			snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
503 				 k1);
504 
505 		len = sizeof(value) - 1;
506 		result =
507 		    asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
508 
509 		if (result == ASN1_ELEMENT_NOT_FOUND) {
510 			gnutls_assert();
511 			break;
512 		}
513 
514 		if (result != ASN1_VALUE_NOT_FOUND) {
515 			gnutls_assert();
516 			result = _gnutls_asn2err(result);
517 			goto cleanup;
518 		}
519 
520 		k2 = 0;
521 
522 		do {		/* Move to the attribute type and values
523 				 */
524 			k2++;
525 
526 			if (tmpbuffer1[0] != 0)
527 				snprintf(tmpbuffer2, sizeof(tmpbuffer2),
528 					 "%s.?%u", tmpbuffer1, k2);
529 			else
530 				snprintf(tmpbuffer2, sizeof(tmpbuffer2),
531 					 "?%u", k2);
532 
533 			/* Try to read the RelativeDistinguishedName attributes.
534 			 */
535 
536 			len = sizeof(value) - 1;
537 			result =
538 			    asn1_read_value(asn1_struct, tmpbuffer2, value,
539 					    &len);
540 
541 			if (result == ASN1_ELEMENT_NOT_FOUND) {
542 				break;
543 			}
544 			if (result != ASN1_VALUE_NOT_FOUND) {
545 				gnutls_assert();
546 				result = _gnutls_asn2err(result);
547 				goto cleanup;
548 			}
549 
550 			/* Read the OID
551 			 */
552 			_gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
553 					tmpbuffer2);
554 			_gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
555 					".type");
556 
557 			len = sizeof(oid) - 1;
558 			result =
559 			    asn1_read_value(asn1_struct, tmpbuffer3, oid,
560 					    &len);
561 
562 			if (result == ASN1_ELEMENT_NOT_FOUND)
563 				break;
564 			else if (result != ASN1_SUCCESS) {
565 				gnutls_assert();
566 				result = _gnutls_asn2err(result);
567 				goto cleanup;
568 			}
569 
570 			if (indx == i++) {	/* Found the OID */
571 
572 				len = strlen(oid) + 1;
573 
574 				if (*sizeof_oid < (unsigned) len) {
575 					*sizeof_oid = len;
576 					gnutls_assert();
577 					return
578 					    GNUTLS_E_SHORT_MEMORY_BUFFER;
579 				}
580 
581 				memcpy(_oid, oid, len);
582 				*sizeof_oid = len - 1;
583 
584 				return 0;
585 			}
586 		}
587 		while (1);
588 
589 	}
590 	while (1);
591 
592 	gnutls_assert();
593 
594 	result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
595 
596       cleanup:
597 	return result;
598 }
599 
600 /* This will write the AttributeTypeAndValue field. The data must be already DER encoded.
601  * 'multi' must be (0) if writing an AttributeTypeAndValue, and 1 if Attribute.
602  * In all cases only one value is written.
603  */
604 static int
_gnutls_x509_write_attribute(const char * given_oid,ASN1_TYPE asn1_struct,const char * where,const void * _data,int sizeof_data)605 _gnutls_x509_write_attribute(const char *given_oid,
606 			     ASN1_TYPE asn1_struct, const char *where,
607 			     const void *_data, int sizeof_data)
608 {
609 	char tmp[128];
610 	int result;
611 
612 	/* write the data (value)
613 	 */
614 
615 	_gnutls_str_cpy(tmp, sizeof(tmp), where);
616 	_gnutls_str_cat(tmp, sizeof(tmp), ".value");
617 
618 	result = asn1_write_value(asn1_struct, tmp, _data, sizeof_data);
619 	if (result < 0) {
620 		gnutls_assert();
621 		return _gnutls_asn2err(result);
622 	}
623 
624 	/* write the type
625 	 */
626 	_gnutls_str_cpy(tmp, sizeof(tmp), where);
627 	_gnutls_str_cat(tmp, sizeof(tmp), ".type");
628 
629 	result = asn1_write_value(asn1_struct, tmp, given_oid, 1);
630 	if (result != ASN1_SUCCESS) {
631 		gnutls_assert();
632 		return _gnutls_asn2err(result);
633 	}
634 
635 	return 0;
636 }
637 
638 
639 /* Decodes an X.509 Attribute (if multi==1) or an AttributeTypeAndValue
640  * otherwise.
641  *
642  * octet_string should be non-zero if we are to decode octet strings after
643  * decoding.
644  *
645  * The output is allocated and stored in value.
646  */
647 int
_gnutls_x509_decode_and_read_attribute(ASN1_TYPE asn1_struct,const char * where,char * oid,int oid_size,gnutls_datum_t * value,int multi,int octet_string)648 _gnutls_x509_decode_and_read_attribute(ASN1_TYPE asn1_struct,
649 				       const char *where, char *oid,
650 				       int oid_size,
651 				       gnutls_datum_t * value, int multi,
652 				       int octet_string)
653 {
654 	char tmpbuffer[128];
655 	int len, result;
656 
657 	/* Read the OID
658 	 */
659 	_gnutls_str_cpy(tmpbuffer, sizeof(tmpbuffer), where);
660 	_gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer), ".type");
661 
662 	len = oid_size - 1;
663 	result = asn1_read_value(asn1_struct, tmpbuffer, oid, &len);
664 
665 	if (result != ASN1_SUCCESS) {
666 		gnutls_assert();
667 		result = _gnutls_asn2err(result);
668 		return result;
669 	}
670 
671 	/* Read the Value
672 	 */
673 
674 	_gnutls_str_cpy(tmpbuffer, sizeof(tmpbuffer), where);
675 	_gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer), ".value");
676 
677 	if (multi)
678 		_gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer), "s.?1");	/* .values.?1 */
679 
680 	if (octet_string)
681 		result =
682 		    _gnutls_x509_read_string(asn1_struct, tmpbuffer, value,
683 					     ASN1_ETYPE_OCTET_STRING, 0);
684 	else
685 		result =
686 		    _gnutls_x509_read_value(asn1_struct, tmpbuffer, value);
687 	if (result < 0) {
688 		gnutls_assert();
689 		return result;
690 	}
691 
692 	return 0;
693 
694 }
695 
696 /* Sets an X509 DN in the asn1_struct, and puts the given OID in the DN.
697  * The input is assumed to be raw data.
698  *
699  * asn1_rdn_name must be a string in the form "tbsCertificate.issuer".
700  * That is to point before the rndSequence.
701  *
702  */
703 int
_gnutls_x509_set_dn_oid(ASN1_TYPE asn1_struct,const char * asn1_name,const char * given_oid,int raw_flag,const char * name,int sizeof_name)704 _gnutls_x509_set_dn_oid(ASN1_TYPE asn1_struct,
705 			const char *asn1_name, const char *given_oid,
706 			int raw_flag, const char *name, int sizeof_name)
707 {
708 	int result;
709 	char tmp[MAX_NAME_SIZE], asn1_rdn_name[MAX_NAME_SIZE];
710 
711 	if (sizeof_name == 0 || name == NULL) {
712 		gnutls_assert();
713 		return GNUTLS_E_INVALID_REQUEST;
714 	}
715 
716 	/* create the rdnSequence
717 	 */
718 	result =
719 	    asn1_write_value(asn1_struct, asn1_name, "rdnSequence", 1);
720 	if (result != ASN1_SUCCESS) {
721 		gnutls_assert();
722 		return _gnutls_asn2err(result);
723 	}
724 
725 	if (asn1_name[0] != 0) {
726 		_gnutls_str_cpy(asn1_rdn_name, sizeof(asn1_rdn_name), asn1_name);
727 		_gnutls_str_cat(asn1_rdn_name, sizeof(asn1_rdn_name),
728 			".rdnSequence");
729 	} else {
730 		_gnutls_str_cpy(asn1_rdn_name, sizeof(asn1_rdn_name), "rdnSequence");
731 	}
732 
733 	/* create a new element
734 	 */
735 	result = asn1_write_value(asn1_struct, asn1_rdn_name, "NEW", 1);
736 	if (result != ASN1_SUCCESS) {
737 		gnutls_assert();
738 		return _gnutls_asn2err(result);
739 	}
740 
741 	_gnutls_str_cpy(tmp, sizeof(tmp), asn1_rdn_name);
742 	_gnutls_str_cat(tmp, sizeof(tmp), ".?LAST");
743 
744 	/* create the set with only one element
745 	 */
746 	result = asn1_write_value(asn1_struct, tmp, "NEW", 1);
747 	if (result != ASN1_SUCCESS) {
748 		gnutls_assert();
749 		return _gnutls_asn2err(result);
750 	}
751 
752 
753 	/* Encode and write the data
754 	 */
755 	_gnutls_str_cpy(tmp, sizeof(tmp), asn1_rdn_name);
756 	_gnutls_str_cat(tmp, sizeof(tmp), ".?LAST.?LAST");
757 
758 	if (!raw_flag) {
759 		result =
760 		    _gnutls_x509_encode_and_write_attribute(given_oid,
761 							    asn1_struct,
762 							    tmp, name,
763 							    sizeof_name,
764 							    0);
765 	} else {
766 		result =
767 		    _gnutls_x509_write_attribute(given_oid, asn1_struct,
768 						 tmp, name, sizeof_name);
769 	}
770 
771 	if (result < 0) {
772 		gnutls_assert();
773 		return result;
774 	}
775 
776 	return 0;
777 }
778 
779 
780 /**
781  * gnutls_x509_rdn_get:
782  * @idn: should contain a DER encoded RDN sequence
783  * @buf: a pointer to a structure to hold the peer's name
784  * @buf_size: holds the size of @buf
785  *
786  * This function will return the name of the given RDN sequence.  The
787  * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
788  * RFC4514.
789  *
790  * This function does not output a fully RFC4514 compliant string, if
791  * that is required see gnutls_x509_rdn_get2().
792  *
793  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
794  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
795  * updated if the provided buffer is not long enough, otherwise a
796  * negative error value.
797  **/
798 int
gnutls_x509_rdn_get(const gnutls_datum_t * idn,char * buf,size_t * buf_size)799 gnutls_x509_rdn_get(const gnutls_datum_t * idn,
800 		    char *buf, size_t * buf_size)
801 {
802 	int ret;
803 	gnutls_datum_t out;
804 
805 	ret = gnutls_x509_rdn_get2(idn, &out, GNUTLS_X509_DN_FLAG_COMPAT);
806 	if (ret < 0)
807 		return gnutls_assert_val(ret);
808 
809 	ret = _gnutls_copy_string(&out, (void*)buf, buf_size);
810 	gnutls_free(out.data);
811 	if (ret < 0) {
812 		gnutls_assert();
813 	}
814 
815 	return ret;
816 }
817 
818 /**
819  * gnutls_x509_rdn_get2:
820  * @idn: should contain a DER encoded RDN sequence
821  * @str: a datum that will hold the name
822  * @flags: zero of %GNUTLS_X509_DN_FLAG_COMPAT
823  *
824  * This function will return the name of the given RDN sequence.  The
825  * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
826  * RFC4514.
827  *
828  * When the flag %GNUTLS_X509_DN_FLAG_COMPAT is specified, the output
829  * format will match the format output by previous to 3.5.6 versions of GnuTLS
830  * which was not not fully RFC4514-compliant.
831  *
832  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
833  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
834  * updated if the provided buffer is not long enough, otherwise a
835  * negative error value.
836  **/
837 int
gnutls_x509_rdn_get2(const gnutls_datum_t * idn,gnutls_datum_t * str,unsigned flags)838 gnutls_x509_rdn_get2(const gnutls_datum_t * idn,
839 		     gnutls_datum_t *str, unsigned flags)
840 {
841 	int ret;
842 	gnutls_x509_dn_t dn;
843 
844 	ret = gnutls_x509_dn_init(&dn);
845 	if (ret < 0)
846 		return gnutls_assert_val(ret);
847 
848 	ret = gnutls_x509_dn_import(dn, idn);
849 	if (ret < 0) {
850 		gnutls_assert();
851 		goto cleanup;
852 	}
853 
854 	ret = gnutls_x509_dn_get_str2(dn, str, flags);
855 	if (ret < 0) {
856 		gnutls_assert();
857 		goto cleanup;
858 	}
859 
860 	ret = 0;
861  cleanup:
862 	gnutls_x509_dn_deinit(dn);
863 	return ret;
864 }
865 
866 /**
867  * gnutls_x509_rdn_get_by_oid:
868  * @idn: should contain a DER encoded RDN sequence
869  * @oid: an Object Identifier
870  * @indx: In case multiple same OIDs exist in the RDN indicates which
871  *   to send. Use 0 for the first one.
872  * @raw_flag: If non-zero then the raw DER data are returned.
873  * @buf: a pointer to a structure to hold the peer's name
874  * @buf_size: holds the size of @buf
875  *
876  * This function will return the name of the given Object identifier,
877  * of the RDN sequence.  The name will be encoded using the rules
878  * from RFC4514.
879  *
880  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
881  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
882  * updated if the provided buffer is not long enough, otherwise a
883  * negative error value.
884  **/
885 int
gnutls_x509_rdn_get_by_oid(const gnutls_datum_t * idn,const char * oid,unsigned indx,unsigned int raw_flag,void * buf,size_t * buf_size)886 gnutls_x509_rdn_get_by_oid(const gnutls_datum_t * idn, const char *oid,
887 			   unsigned indx, unsigned int raw_flag,
888 			   void *buf, size_t * buf_size)
889 {
890 	int result;
891 	ASN1_TYPE dn = ASN1_TYPE_EMPTY;
892 	gnutls_datum_t td;
893 
894 	if (buf_size == 0) {
895 		return GNUTLS_E_INVALID_REQUEST;
896 	}
897 
898 	if ((result =
899 	     asn1_create_element(_gnutls_get_pkix(),
900 				 "PKIX1.Name", &dn)) != ASN1_SUCCESS) {
901 		gnutls_assert();
902 		return _gnutls_asn2err(result);
903 	}
904 
905 	result = _asn1_strict_der_decode(&dn, idn->data, idn->size, NULL);
906 	if (result != ASN1_SUCCESS) {
907 		/* couldn't decode DER */
908 		gnutls_assert();
909 		asn1_delete_structure(&dn);
910 		return _gnutls_asn2err(result);
911 	}
912 
913 	result =
914 	    _gnutls_x509_parse_dn_oid(dn, "rdnSequence", oid, indx,
915 				      raw_flag, &td);
916 
917 	asn1_delete_structure(&dn);
918 	if (result < 0)
919 		return gnutls_assert_val(result);
920 
921 	return _gnutls_strdatum_to_buf(&td, buf, buf_size);
922 }
923 
924 /**
925  * gnutls_x509_rdn_get_oid:
926  * @idn: should contain a DER encoded RDN sequence
927  * @indx: Indicates which OID to return. Use 0 for the first one.
928  * @buf: a pointer to a structure to hold the peer's name OID
929  * @buf_size: holds the size of @buf
930  *
931  * This function will return the specified Object identifier, of the
932  * RDN sequence.
933  *
934  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
935  * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
936  * updated if the provided buffer is not long enough, otherwise a
937  * negative error value.
938  *
939  * Since: 2.4.0
940  **/
941 int
gnutls_x509_rdn_get_oid(const gnutls_datum_t * idn,unsigned indx,void * buf,size_t * buf_size)942 gnutls_x509_rdn_get_oid(const gnutls_datum_t * idn,
943 			unsigned indx, void *buf, size_t * buf_size)
944 {
945 	int result;
946 	ASN1_TYPE dn = ASN1_TYPE_EMPTY;
947 
948 	if (buf_size == 0) {
949 		return GNUTLS_E_INVALID_REQUEST;
950 	}
951 
952 	if ((result =
953 	     asn1_create_element(_gnutls_get_pkix(),
954 				 "PKIX1.Name", &dn)) != ASN1_SUCCESS) {
955 		gnutls_assert();
956 		return _gnutls_asn2err(result);
957 	}
958 
959 	result = _asn1_strict_der_decode(&dn, idn->data, idn->size, NULL);
960 	if (result != ASN1_SUCCESS) {
961 		/* couldn't decode DER */
962 		gnutls_assert();
963 		asn1_delete_structure(&dn);
964 		return _gnutls_asn2err(result);
965 	}
966 
967 	result =
968 	    _gnutls_x509_get_dn_oid(dn, "rdnSequence", indx, buf,
969 				    buf_size);
970 
971 	asn1_delete_structure(&dn);
972 	return result;
973 }
974 
975 /*
976  * Compares the DER encoded part of a DN.
977  *
978  * Returns 1 if the DN's match and (0) if they don't match. Otherwise
979  * a negative error code is returned to indicate error.
980  */
981 int
_gnutls_x509_compare_raw_dn(const gnutls_datum_t * dn1,const gnutls_datum_t * dn2)982 _gnutls_x509_compare_raw_dn(const gnutls_datum_t * dn1,
983 			    const gnutls_datum_t * dn2)
984 {
985 	int ret;
986 	gnutls_datum_t str1, str2;
987 
988 	/* Simple case of completely identical? */
989 
990 	if (dn1->size == dn2->size) {
991 		if (memcmp(dn1->data, dn2->data, dn2->size) == 0) {
992 			return 1;
993 		}
994 	}
995 
996 	/* RFC5280 (https://tools.ietf.org/html/rfc5280#section-7.1)
997 	 * requires that the LDAP StringPrep profile and caseIgnoreMatch
998 	 * must be used for this comparison. We do not use that but
999 	 * instead we do a simpler comparison that ignores the tags used
1000 	 * such as `UTF8String` and `PrintableString`. */
1001 
1002 	if ((dn1->size == 0) || (dn2->size == 0)) {
1003 		gnutls_assert();
1004 		return 0;
1005 	}
1006 
1007 	ret = gnutls_x509_rdn_get2(dn1, &str1, 0);
1008 	if (ret < 0) {
1009 		gnutls_assert();
1010 		return 0;
1011 	}
1012 
1013 	ret = gnutls_x509_rdn_get2(dn2, &str2, 0);
1014 	if (ret < 0) {
1015 		gnutls_assert();
1016 		_gnutls_free_datum(&str1);
1017 		return 0;
1018 	}
1019 
1020 	if (str1.size != str2.size) {
1021 		ret = 0;
1022 		goto cleanup;
1023 	}
1024 	if (memcmp(str1.data, str2.data, str2.size) != 0) {
1025 		gnutls_assert();
1026 		ret = 0;
1027 		goto cleanup;
1028 	}
1029 
1030 	ret = 1;		/* they match */
1031 
1032 cleanup:
1033 	_gnutls_free_datum(&str1);
1034 	_gnutls_free_datum(&str2);
1035 
1036 	return ret;
1037 }
1038