Applied Jeff Johnson's patch which fixes type problems in 64 bit machines. Removed...
[gnutls.git] / lib / auth_cert.c
blob95a7b3aa14f290669529e5a4b0649fe840042494
1 /*
2 * Copyright (C) 2001,2002 Nikos Mavroyanopoulos
4 * This file is part of GNUTLS.
6 * The GNUTLS library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * */
21 #include <gnutls_int.h>
22 #include "gnutls_auth_int.h"
23 #include "gnutls_errors.h"
24 #include <gnutls_cert.h>
25 #include <auth_cert.h>
26 #include "gnutls_dh.h"
27 #include "gnutls_num.h"
28 #include "x509_asn1.h"
29 #include "x509_der.h"
30 #include "gnutls_datum.h"
31 #include <gnutls_random.h>
32 #include <gnutls_pk.h>
33 #include <gnutls_algorithms.h>
34 #include <gnutls_global.h>
35 #include <gnutls_record.h>
36 #include <x509_verify.h>
37 #include <gnutls_sig.h>
38 #include <x509_extensions.h>
39 #include <gnutls_state.h>
40 #include <gnutls_pk.h>
41 #include <gnutls_x509.h>
42 #include <gnutls_extra.h>
43 #include "debug.h"
45 /* Copies data from a internal certificate struct (gnutls_cert) to
46 * exported certificate struct (CERTIFICATE_AUTH_INFO)
48 static
49 int _gnutls_copy_certificate_auth_info(CERTIFICATE_AUTH_INFO info,
50 gnutls_cert * cert, int ncerts)
52 /* Copy peer's information to AUTH_INFO
54 int ret, i, j;
56 if (ncerts == 0) {
57 info->raw_certificate_list = NULL;
58 info->ncerts = 0;
59 return 0;
62 info->raw_certificate_list =
63 gnutls_calloc(1, sizeof(gnutls_datum) * ncerts);
64 if (info->raw_certificate_list == NULL) {
65 gnutls_assert();
66 return GNUTLS_E_MEMORY_ERROR;
69 for (i = 0; i < ncerts; i++) {
70 if (cert->raw.size > 0) {
71 ret =
72 gnutls_set_datum(&info->
73 raw_certificate_list[i],
74 cert[i].raw.data,
75 cert[i].raw.size);
76 if (ret < 0) {
77 gnutls_assert();
78 goto clear;
82 info->ncerts = ncerts;
84 return 0;
86 clear:
88 for (j = 0; j < i; j++)
89 gnutls_free_datum(&info->raw_certificate_list[j]);
91 gnutls_free(info->raw_certificate_list);
92 info->raw_certificate_list = NULL;
94 return ret;
98 /* Returns the issuer's Distinguished name in odn, of the certificate
99 * specified in cert.
101 int _gnutls_find_dn(gnutls_datum * odn, gnutls_cert * cert)
103 node_asn *dn;
104 int len, result;
105 int start, end;
107 if ((result=asn1_create_structure
108 (_gnutls_get_pkix(), "PKIX1.Certificate", &dn,
109 "dn")) != ASN_OK) {
110 gnutls_assert();
111 return _gnutls_asn2err(result);
114 result = asn1_get_der(dn, cert->raw.data, cert->raw.size);
115 if (result != ASN_OK) {
116 /* couldn't decode DER */
117 gnutls_assert();
118 asn1_delete_structure(dn);
119 return _gnutls_asn2err(result);
122 result = asn1_get_start_end_der(dn, cert->raw.data, cert->raw.size,
123 "dn.tbsCertificate.issuer", &start,
124 &end);
126 if (result != ASN_OK) {
127 /* couldn't decode DER */
128 gnutls_assert();
129 asn1_delete_structure(dn);
130 return _gnutls_asn2err(result);
132 asn1_delete_structure(dn);
134 len = end - start + 1;
136 odn->size = len;
137 odn->data = &cert->raw.data[start];
139 return 0;
143 /* returns 0 if the algo_to-check exists in the pk_algos list,
144 * -1 otherwise.
146 inline
147 static int _gnutls_check_pk_algo_in_list(PKAlgorithm * pk_algos,
148 int pk_algos_length,
149 PKAlgorithm algo_to_check)
151 int i;
152 for (i = 0; i < pk_algos_length; i++) {
153 if (algo_to_check == pk_algos[i]) {
154 return 0;
157 return -1;
160 /* Locates the most appropriate x509 certificate using the
161 * given DN. If indx == -1 then no certificate was found.
163 static int _find_x509_cert(const GNUTLS_CERTIFICATE_CREDENTIALS cred,
164 opaque * _data, int _data_size,
165 PKAlgorithm * pk_algos, int pk_algos_length,
166 int *indx)
168 int size;
169 gnutls_datum odn;
170 opaque *data = _data;
171 int data_size = _data_size, i, j;
172 int result;
174 *indx = -1;
176 do {
178 DECR_LENGTH_RET(data_size, 2, 0);
179 size = _gnutls_read_uint16(data);
180 DECR_LENGTH_RET(data_size, size, 0);
181 data += 2;
183 for (i = 0; i < cred->ncerts; i++) {
184 for (j = 0; j < cred->cert_list_length[i]; j++) {
185 if ((result =
186 _gnutls_find_dn(&odn,
187 &cred->cert_list[i]
188 [j])) < 0) {
189 gnutls_assert();
190 return result;
193 if (odn.size != size)
194 continue;
196 /* If the DN matches and
197 * the *_SIGN algorithm matches
198 * the cert is our cert!
200 if ((memcmp(odn.data,
201 data, size) == 0) &&
202 (_gnutls_check_pk_algo_in_list
203 (pk_algos, pk_algos_length,
204 cred->cert_list[i][0].
205 subject_pk_algorithm) == 0)
206 && (cred->cert_list[i][0].cert_type ==
207 GNUTLS_CRT_X509)) {
208 *indx = i;
209 break;
212 if (*indx != -1)
213 break;
216 if (*indx != -1)
217 break;
219 /* move to next record */
220 if (data_size <= 0)
221 break;
223 data += size;
225 } while (1);
227 return 0;
231 /* Locates the most appropriate openpgp cert
233 static int _find_openpgp_cert(const GNUTLS_CERTIFICATE_CREDENTIALS cred,
234 PKAlgorithm * pk_algos, int pk_algos_length,
235 int *indx)
237 int i, j;
239 *indx = -1;
241 for (i = 0; i < cred->ncerts; i++) {
242 for (j = 0; j < cred->cert_list_length[i]; j++) {
244 /* If the *_SIGN algorithm matches
245 * the cert is our cert!
247 if ((_gnutls_check_pk_algo_in_list
248 (pk_algos, pk_algos_length,
249 cred->cert_list[i][0].
250 subject_pk_algorithm) == 0)
251 && (cred->cert_list[i][0].cert_type ==
252 GNUTLS_CRT_OPENPGP)) {
253 *indx = i;
254 break;
257 if (*indx != -1)
258 break;
261 return 0;
264 /* Finds the appropriate certificate depending on the cA Distinguished name
265 * advertized by the server. If none matches then returns 0 and -1 as index.
266 * In case of an error a negative value, is returned.
268 * 20020128: added ability to select a certificate depending on the SIGN
269 * algorithm (only in automatic mode).
271 static int _gnutls_find_acceptable_client_cert(GNUTLS_STATE state,
272 opaque * _data,
273 int _data_size, int *ind,
274 PKAlgorithm * pk_algos,
275 int pk_algos_length)
277 int result, size;
278 int indx = -1;
279 int i, j, try = 0, *ij_map = NULL;
280 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
281 opaque *data = _data;
282 int data_size = _data_size;
284 cred =
285 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
286 NULL);
287 if (cred == NULL) {
288 gnutls_assert();
289 return GNUTLS_E_INSUFICIENT_CRED;
292 if (state->gnutls_internals.client_cert_callback != NULL) {
293 /* if try>=0 then the client wants automatic
294 * choose of certificate, otherwise (-1), he
295 * will be prompted to choose one.
297 try =
298 state->gnutls_internals.client_cert_callback(state,
299 NULL, 0,
300 NULL, 0);
304 if (try >= 0) {
305 result = 0;
307 if (state->security_parameters.cert_type ==
308 GNUTLS_CRT_X509)
309 result =
310 _find_x509_cert(cred, _data, _data_size,
311 pk_algos, pk_algos_length,
312 &indx);
314 if (state->security_parameters.cert_type ==
315 GNUTLS_CRT_OPENPGP)
316 result =
317 _find_openpgp_cert(cred, pk_algos,
318 pk_algos_length, &indx);
321 if (result < 0) {
322 gnutls_assert();
323 return result;
328 /* use the callback
330 if (indx == -1 && state->gnutls_internals.client_cert_callback != NULL && cred->ncerts > 0) { /* use a callback to get certificate */
331 gnutls_datum *my_certs = NULL;
332 gnutls_datum *issuers_dn = NULL;
333 int issuers_dn_len = 0;
334 opaque* dataptr = data;
335 int dataptr_size = data_size;
337 /* Count the number of the given issuers;
338 * This is used to allocate the issuers_dn without
339 * using realloc().
341 do {
342 dataptr_size -= 2;
343 if (dataptr_size <= 0)
344 goto clear;
345 size = _gnutls_read_uint16(data);
347 dataptr_size -= size;
348 if (dataptr_size < 0)
349 goto clear;
351 dataptr += 2;
353 issuers_dn_len++;
355 dataptr += size;
357 if (dataptr_size == 0)
358 break;
360 } while (1);
363 my_certs =
364 gnutls_alloca(cred->ncerts * sizeof(gnutls_datum));
365 if (my_certs == NULL)
366 goto clear;
368 /* put the requested DNs to req_dn, only in case
369 * of X509 certificates.
371 if (gnutls_cert_type_get(state) == GNUTLS_CRT_X509) {
372 data = _data;
373 data_size = _data_size;
375 issuers_dn = gnutls_alloca( issuers_dn_len * sizeof(gnutls_datum));
376 if (issuers_dn == NULL)
377 goto clear;
379 for (i=0;i<issuers_dn_len;i++) {
380 /* The checks here for the buffer boundaries
381 * are not needed since the buffer has been
382 * parsed above.
384 data_size -= 2;
386 size = _gnutls_read_uint16(data);
388 data += 2;
390 issuers_dn[i].data = data;
391 issuers_dn[i].size = size;
393 data += size;
397 } else { /* Other certificate types */
398 issuers_dn_len = 0;
399 issuers_dn = NULL;
402 /* maps j -> i */
403 ij_map = gnutls_alloca(sizeof(int) * cred->ncerts);
404 if (ij_map==NULL) {
405 gnutls_assert();
406 goto clear;
409 /* put our certificate's issuer and dn into cdn, idn
410 * Note that the certificates we provide to the callback
411 * are not all the certificates we have. Only the certificates
412 * that are requested by the server (CA matches - and sign
413 * algorithm matches), are provided.
415 for (j = i = 0; i < cred->ncerts; i++) {
416 if ((cred->cert_list[i][0].cert_type ==
417 gnutls_cert_type_get(state)) &&
418 (_gnutls_check_pk_algo_in_list(pk_algos,
419 pk_algos_length,
420 cred->
421 cert_list[i][0].
422 subject_pk_algorithm)
423 == 0)) {
424 /* Add a certificate ONLY if it is allowed
425 * by the peer.
427 ij_map[j] = i;
428 my_certs[j++] = cred->cert_list[i][0].raw;
432 indx =
433 state->gnutls_internals.client_cert_callback(state,
434 my_certs,
436 issuers_dn,
437 issuers_dn_len);
439 /* the indx returned by the user is relative
440 * to the certificates we provided him.
441 * This will make it relative to the certificates
442 * we've got.
444 indx = ij_map[indx];
446 clear:
447 gnutls_afree(my_certs);
448 gnutls_afree(ij_map);
449 gnutls_afree(issuers_dn);
452 *ind = indx;
453 return 0;
456 /* Generate client certificate
459 int _gnutls_gen_x509_certificate(GNUTLS_STATE state, opaque ** data)
461 int ret, i;
462 opaque *pdata;
463 gnutls_cert *apr_cert_list;
464 gnutls_private_key *apr_pkey;
465 int apr_cert_list_length;
467 /* find the appropriate certificate */
468 if ((ret =
469 _gnutls_find_apr_cert(state, &apr_cert_list,
470 &apr_cert_list_length,
471 &apr_pkey)) < 0) {
472 gnutls_assert();
473 return ret;
476 ret = 3;
477 for (i = 0; i < apr_cert_list_length; i++) {
478 ret += apr_cert_list[i].raw.size + 3;
479 /* hold size
480 * for uint24 */
483 /* if no certificates were found then send:
484 * 0B 00 00 03 00 00 00 // Certificate with no certs
485 * instead of:
486 * 0B 00 00 00 // empty certificate handshake
488 * ( the above is the whole handshake message, not
489 * the one produced here )
492 (*data) = gnutls_malloc(ret);
493 pdata = (*data);
495 if (pdata == NULL) {
496 gnutls_assert();
497 return GNUTLS_E_MEMORY_ERROR;
499 _gnutls_write_uint24(ret - 3, pdata);
500 pdata += 3;
501 for (i = 0; i < apr_cert_list_length; i++) {
502 _gnutls_write_datum24(pdata, apr_cert_list[i].raw);
503 pdata += (3 + apr_cert_list[i].raw.size);
506 return ret;
509 enum PGPKeyDescriptorType { PGP_KEY_FINGERPRINT, PGP_KEY };
511 int _gnutls_gen_openpgp_certificate(GNUTLS_STATE state,
512 opaque ** data)
514 int ret;
515 opaque *pdata;
516 gnutls_cert *apr_cert_list;
517 gnutls_private_key *apr_pkey;
518 int apr_cert_list_length;
520 /* find the appropriate certificate */
521 if ((ret =
522 _gnutls_find_apr_cert(state, &apr_cert_list,
523 &apr_cert_list_length,
524 &apr_pkey)) < 0) {
525 gnutls_assert();
526 return ret;
529 ret = 3 + 1 + 3;
531 if (apr_cert_list_length > 0)
532 ret += apr_cert_list[0].raw.size;
534 (*data) = gnutls_malloc(ret);
535 pdata = (*data);
537 if (pdata == NULL) {
538 gnutls_assert();
539 return GNUTLS_E_MEMORY_ERROR;
542 _gnutls_write_uint24(ret - 3, pdata);
543 pdata += 3;
545 *pdata = PGP_KEY; /* whole key */
546 pdata++;
548 if (apr_cert_list_length > 0) {
549 _gnutls_write_datum24(pdata, apr_cert_list[0].raw);
550 pdata += (3 + apr_cert_list[0].raw.size);
551 } else /* empty - no certificate */
552 _gnutls_write_uint24(0, pdata);
554 return ret;
557 OPENPGP_FINGERPRINT _E_gnutls_openpgp_fingerprint = NULL;
558 OPENPGP_KEY_REQUEST _E_gnutls_openpgp_request_key = NULL;
559 extern OPENPGP_CERT2GNUTLS_CERT _E_gnutls_openpgp_cert2gnutls_cert;
561 int _gnutls_gen_openpgp_certificate_fpr(GNUTLS_STATE state,
562 opaque ** data)
564 int ret, fpr_size, packet_size;
565 opaque *pdata;
566 gnutls_cert *apr_cert_list;
567 gnutls_private_key *apr_pkey;
568 int apr_cert_list_length;
570 /* find the appropriate certificate */
571 if ((ret =
572 _gnutls_find_apr_cert(state, &apr_cert_list,
573 &apr_cert_list_length,
574 &apr_pkey)) < 0) {
575 gnutls_assert();
576 return ret;
579 packet_size = 3 + 1;
581 /* Only v4 fingerprints are sent
583 if (apr_cert_list_length > 0 && apr_cert_list[0].version == 4)
584 packet_size += 20 + 1;
585 else /* empty certificate case */
586 return _gnutls_gen_openpgp_certificate(state, data);
588 (*data) = gnutls_malloc(packet_size);
589 pdata = (*data);
591 if (pdata == NULL) {
592 gnutls_assert();
593 return GNUTLS_E_MEMORY_ERROR;
596 _gnutls_write_uint24(packet_size - 3, pdata);
597 pdata += 3;
599 *pdata = PGP_KEY_FINGERPRINT; /* key fingerprint */
600 pdata++;
602 *pdata = 20;
603 pdata++;
605 fpr_size = 20;
607 if (_E_gnutls_openpgp_fingerprint==NULL) {
608 gnutls_assert();
609 return GNUTLS_E_INVALID_REQUEST;
612 if ( (ret=_E_gnutls_openpgp_fingerprint( &apr_cert_list[0].raw, pdata, &fpr_size)) < 0) {
613 gnutls_assert();
614 return ret;
617 return packet_size;
622 int _gnutls_gen_cert_client_certificate(GNUTLS_STATE state, opaque ** data)
624 switch (state->security_parameters.cert_type) {
625 case GNUTLS_CRT_OPENPGP:
626 if (_gnutls_openpgp_send_fingerprint(state) == 0)
627 return
628 _gnutls_gen_openpgp_certificate(state,
629 data);
630 else
631 return
632 _gnutls_gen_openpgp_certificate_fpr
633 (state, data);
635 case GNUTLS_CRT_X509:
636 return _gnutls_gen_x509_certificate(state, data);
638 default:
639 gnutls_assert();
640 return GNUTLS_E_UNKNOWN_ERROR;
644 int _gnutls_gen_cert_server_certificate(GNUTLS_STATE state, opaque ** data)
646 switch (state->security_parameters.cert_type) {
647 case GNUTLS_CRT_OPENPGP:
648 return _gnutls_gen_openpgp_certificate(state, data);
649 case GNUTLS_CRT_X509:
650 return _gnutls_gen_x509_certificate(state, data);
651 default:
652 gnutls_assert();
653 return GNUTLS_E_UNKNOWN_ERROR;
657 /* Process server certificate
660 #define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(peer_certificate_list[x])
661 int _gnutls_proc_x509_server_certificate(GNUTLS_STATE state, opaque * data,
662 int data_size)
664 int size, len, ret;
665 opaque *p = data;
666 CERTIFICATE_AUTH_INFO info;
667 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
668 int dsize = data_size;
669 int i, j, x;
670 gnutls_cert *peer_certificate_list;
671 int peer_certificate_list_size = 0;
672 gnutls_datum tmp;
674 cred =
675 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
676 NULL);
677 if (cred == NULL) {
678 gnutls_assert();
679 return GNUTLS_E_INSUFICIENT_CRED;
683 if ((ret =
684 _gnutls_auth_info_set(state, GNUTLS_CRD_CERTIFICATE,
685 sizeof(CERTIFICATE_AUTH_INFO_INT), 1)) <
686 0) {
687 gnutls_assert();
688 return ret;
691 info = _gnutls_get_auth_info(state);
693 if (data == NULL || data_size == 0) {
694 gnutls_assert();
695 /* no certificate was sent */
696 return GNUTLS_E_NO_CERTIFICATE_FOUND;
699 DECR_LEN(dsize, 3);
700 size = _gnutls_read_uint24(p);
701 p += 3;
703 if (size == 0) {
704 gnutls_assert();
705 /* no certificate was sent */
706 return GNUTLS_E_NO_CERTIFICATE_FOUND;
709 i = dsize;
710 while(i > 0) {
711 DECR_LEN(dsize, 3);
712 len = _gnutls_read_uint24(p);
713 p += 3;
714 DECR_LEN(dsize, len);
715 peer_certificate_list_size++;
716 p += len;
717 i -= len + 3;
720 if (peer_certificate_list_size == 0) {
721 gnutls_assert();
722 return GNUTLS_E_NO_CERTIFICATE_FOUND;
725 /* Ok we now allocate the memory to hold the
726 * certificate list
729 peer_certificate_list =
730 gnutls_alloca( sizeof(gnutls_cert) *
731 (peer_certificate_list_size));
733 if (peer_certificate_list == NULL) {
734 gnutls_assert();
735 return GNUTLS_E_MEMORY_ERROR;
737 memset( peer_certificate_list, 0, sizeof(gnutls_cert)*
738 peer_certificate_list_size);
740 p = data + 3;
742 /* Now we start parsing the list (again).
743 * We don't use DECR_LEN since the list has
744 * been parsed before.
747 for (j=0;j<peer_certificate_list_size;j++) {
748 len = _gnutls_read_uint24(p);
749 p += 3;
751 tmp.size = len;
752 tmp.data = p;
754 if ((ret =
755 _gnutls_x509_cert2gnutls_cert(&peer_certificate_list
756 [j], tmp)) < 0) {
757 gnutls_assert();
758 CLEAR_CERTS;
759 gnutls_afree(peer_certificate_list);
760 return ret;
763 p += len;
767 if ((ret =
768 _gnutls_copy_certificate_auth_info(info,
769 peer_certificate_list,
770 peer_certificate_list_size))
771 < 0) {
772 gnutls_assert();
773 CLEAR_CERTS;
774 gnutls_afree(peer_certificate_list);
775 return ret;
778 if ((ret =
779 _gnutls_check_x509_key_usage(&peer_certificate_list[0],
780 gnutls_kx_get(state)))
781 < 0) {
782 gnutls_assert();
783 CLEAR_CERTS;
784 gnutls_afree(peer_certificate_list);
785 return ret;
788 CLEAR_CERTS;
789 gnutls_afree(peer_certificate_list);
791 return 0;
794 #define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(peer_certificate_list[x])
795 int _gnutls_proc_openpgp_server_certificate(GNUTLS_STATE state,
796 opaque * data, int data_size)
798 int size, ret, len;
799 opaque *p = data;
800 CERTIFICATE_AUTH_INFO info;
801 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
802 int dsize = data_size;
803 int i, x;
804 gnutls_cert *peer_certificate_list;
805 int peer_certificate_list_size = 0;
806 gnutls_datum tmp, akey = { NULL, 0 };
808 cred =
809 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
810 NULL);
811 if (cred == NULL) {
812 gnutls_assert();
813 return GNUTLS_E_INSUFICIENT_CRED;
816 if ((ret =
817 _gnutls_auth_info_set(state, GNUTLS_CRD_CERTIFICATE,
818 sizeof(CERTIFICATE_AUTH_INFO_INT), 1)) <
819 0) {
820 gnutls_assert();
821 return ret;
824 info = _gnutls_get_auth_info(state);
826 if (data == NULL || data_size == 0) {
827 gnutls_assert();
828 return GNUTLS_E_NO_CERTIFICATE_FOUND;
831 DECR_LEN(dsize, 3);
832 size = _gnutls_read_uint24(p);
833 p += 3;
835 if (size == 0) {
836 gnutls_assert();
837 /* no certificate was sent */
838 return GNUTLS_E_NO_CERTIFICATE_FOUND;
840 i = dsize;
842 /* Read PGPKeyDescriptor */
843 DECR_LEN(dsize, 1);
844 if (*p == PGP_KEY_FINGERPRINT) { /* the fingerprint */
845 p++;
847 DECR_LEN(dsize, 1);
848 len = (uint8) *p;
850 if (len != 20) {
851 gnutls_assert();
852 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
855 DECR_LEN( dsize, 20);
857 /* request the actual key from our database, or
858 * a key server or anything.
860 if (_E_gnutls_openpgp_request_key==NULL) {
861 gnutls_assert();
862 return GNUTLS_E_INVALID_REQUEST;
864 if ( (ret=_E_gnutls_openpgp_request_key( &akey, cred, p, 20)) < 0) {
865 gnutls_assert();
866 return ret;
868 tmp = akey;
869 peer_certificate_list_size++;
871 } else if (*p == PGP_KEY) { /* the whole key */
873 p++;
875 /* Read the actual certificate */
876 DECR_LEN(dsize, 3);
877 len = _gnutls_read_uint24(p);
878 p += 3;
880 if (size == 0) {
881 gnutls_assert();
882 /* no certificate was sent */
883 return GNUTLS_E_NO_CERTIFICATE_FOUND;
886 DECR_LEN(dsize, len);
887 peer_certificate_list_size++;
889 tmp.size = len;
890 tmp.data = p;
892 } else {
893 gnutls_assert();
894 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
897 /* ok we now have the peer's key in tmp datum
900 if (peer_certificate_list_size == 0) {
901 gnutls_assert();
902 gnutls_free_datum( &akey);
903 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
906 peer_certificate_list =
907 gnutls_alloca( sizeof(gnutls_cert) *
908 (peer_certificate_list_size));
909 if (peer_certificate_list == NULL) {
910 gnutls_assert();
911 return GNUTLS_E_MEMORY_ERROR;
913 memset( peer_certificate_list, 0, sizeof(gnutls_cert)*
914 peer_certificate_list_size);
916 if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
917 gnutls_assert();
918 gnutls_free_datum( &akey);
919 CLEAR_CERTS;
920 gnutls_afree(peer_certificate_list);
921 return GNUTLS_E_INVALID_REQUEST;
924 if ((ret =
925 _E_gnutls_openpgp_cert2gnutls_cert(&peer_certificate_list[0],
926 tmp)) < 0) {
927 gnutls_assert();
928 gnutls_free_datum( &akey);
929 CLEAR_CERTS;
930 gnutls_afree(peer_certificate_list);
931 return ret;
933 gnutls_free_datum( &akey);
935 if ((ret =
936 _gnutls_copy_certificate_auth_info(info,
937 peer_certificate_list,
938 peer_certificate_list_size))
939 < 0) {
940 gnutls_assert();
941 CLEAR_CERTS;
942 gnutls_afree(peer_certificate_list);
943 return ret;
946 if ((ret =
947 _gnutls_check_x509_key_usage(&peer_certificate_list[0],
948 gnutls_kx_get(state)))
949 < 0) {
950 gnutls_assert();
951 CLEAR_CERTS;
952 gnutls_afree(peer_certificate_list);
953 return ret;
956 CLEAR_CERTS;
957 gnutls_afree(peer_certificate_list);
959 return 0;
962 int _gnutls_proc_cert_server_certificate(GNUTLS_STATE state, opaque * data,
963 int data_size)
965 switch (state->security_parameters.cert_type) {
966 case GNUTLS_CRT_OPENPGP:
967 return _gnutls_proc_openpgp_server_certificate(state, data,
968 data_size);
969 case GNUTLS_CRT_X509:
970 return _gnutls_proc_x509_server_certificate(state, data,
971 data_size);
972 default:
973 gnutls_assert();
974 return GNUTLS_E_UNKNOWN_ERROR;
978 #define MAX_SIGN_ALGOS 2
979 typedef enum CertificateSigType { RSA_SIGN = 1, DSA_SIGN
980 } CertificateSigType;
982 /* Checks if we support the given signature algorithm
983 * (RSA or DSA). Returns the corresponding PKAlgorithm
984 * if true;
986 inline static
987 int _gnutls_check_supported_sign_algo(CertificateSigType algo)
989 switch (algo) {
990 case RSA_SIGN:
991 return GNUTLS_PK_RSA;
992 case DSA_SIGN:
993 return GNUTLS_PK_DSA;
996 return -1;
999 int _gnutls_proc_cert_cert_req(GNUTLS_STATE state, opaque * data,
1000 int data_size)
1002 int size, ret;
1003 opaque *p = data;
1004 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
1005 CERTIFICATE_AUTH_INFO info;
1006 int dsize = data_size;
1007 int i, j, ind;
1008 PKAlgorithm pk_algos[MAX_SIGN_ALGOS];
1009 int pk_algos_length;
1011 cred =
1012 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
1013 NULL);
1014 if (cred == NULL) {
1015 gnutls_assert();
1016 return GNUTLS_E_INSUFICIENT_CRED;
1019 if ((ret =
1020 _gnutls_auth_info_set(state, GNUTLS_CRD_CERTIFICATE,
1021 sizeof(CERTIFICATE_AUTH_INFO_INT), 0)) <
1022 0) {
1023 gnutls_assert();
1024 return ret;
1027 info = _gnutls_get_auth_info(state);
1029 DECR_LEN(dsize, 1);
1030 size = p[0];
1031 p++;
1032 /* check if the sign algorithm is supported.
1034 pk_algos_length = j = 0;
1035 for (i = 0; i < size; i++, p++) {
1036 DECR_LEN(dsize, 1);
1037 if ((ret = _gnutls_check_supported_sign_algo(*p)) > 0) {
1038 if (j < MAX_SIGN_ALGOS) {
1039 pk_algos[j++] = ret;
1040 pk_algos_length++;
1045 if (pk_algos_length == 0) {
1046 gnutls_assert();
1047 return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
1050 if (state->security_parameters.cert_type == GNUTLS_CRT_X509) {
1051 DECR_LEN(dsize, 2);
1052 size = _gnutls_read_uint16(p);
1053 p += 2;
1054 } else {
1055 p = NULL;
1056 size = 0;
1059 DECR_LEN(dsize, size);
1061 /* now we ask the user to tell which one
1062 * he wants to use.
1064 if ((ret =
1065 _gnutls_find_acceptable_client_cert(state, p, size,
1066 &ind, pk_algos,
1067 pk_algos_length)) < 0) {
1068 gnutls_assert();
1069 return ret;
1071 /* put the index of the client certificate to use
1073 state->gnutls_internals.selected_cert_index = ind;
1075 if (ind >= 0)
1076 state->gnutls_key->certificate_requested = 1;
1078 return 0;
1081 int _gnutls_gen_cert_client_cert_vrfy(GNUTLS_STATE state, opaque ** data)
1083 int ret;
1084 gnutls_cert *apr_cert_list;
1085 gnutls_private_key *apr_pkey;
1086 int apr_cert_list_length, size;
1087 gnutls_datum signature;
1089 *data = NULL;
1091 /* find the appropriate certificate */
1092 if ((ret =
1093 _gnutls_find_apr_cert(state, &apr_cert_list,
1094 &apr_cert_list_length,
1095 &apr_pkey)) < 0) {
1096 gnutls_assert();
1097 return ret;
1100 if (apr_pkey != NULL) {
1101 if ((ret =
1102 _gnutls_generate_sig_from_hdata(state,
1103 &apr_cert_list[0],
1104 apr_pkey,
1105 &signature)) < 0) {
1106 gnutls_assert();
1107 return ret;
1109 } else {
1110 gnutls_assert();
1111 return 0;
1114 *data = gnutls_malloc(signature.size + 2);
1115 if (*data == NULL) {
1116 gnutls_free_datum(&signature);
1117 return GNUTLS_E_MEMORY_ERROR;
1119 size = signature.size;
1120 _gnutls_write_uint16(size, *data);
1122 memcpy(&(*data)[2], signature.data, size);
1124 gnutls_free_datum(&signature);
1126 return size + 2;
1129 int _gnutls_proc_cert_client_cert_vrfy(GNUTLS_STATE state, opaque * data,
1130 int data_size)
1132 int size, ret;
1133 int dsize = data_size;
1134 opaque *pdata = data;
1135 gnutls_datum sig;
1136 CERTIFICATE_AUTH_INFO info = _gnutls_get_auth_info(state);
1137 gnutls_cert peer_cert;
1139 if (info == NULL || info->ncerts == 0) {
1140 gnutls_assert();
1141 /* we need this in order to get peer's certificate */
1142 return GNUTLS_E_UNKNOWN_ERROR;
1145 DECR_LEN(dsize, 2);
1146 size = _gnutls_read_uint16(pdata);
1147 pdata += 2;
1149 DECR_LEN(dsize, size);
1151 sig.data = pdata;
1152 sig.size = size;
1154 switch (state->security_parameters.cert_type) {
1155 case GNUTLS_CRT_X509:
1156 ret =
1157 _gnutls_x509_cert2gnutls_cert(&peer_cert,
1158 info->
1159 raw_certificate_list[0]);
1160 break;
1161 case GNUTLS_CRT_OPENPGP:
1162 if (_E_gnutls_openpgp_cert2gnutls_cert==NULL) {
1163 gnutls_assert();
1164 return GNUTLS_E_INVALID_REQUEST;
1166 ret =
1167 _E_gnutls_openpgp_cert2gnutls_cert(&peer_cert,
1168 info->
1169 raw_certificate_list
1170 [0]);
1171 break;
1172 default:
1173 gnutls_assert();
1174 return GNUTLS_E_UNKNOWN_ERROR;
1177 if (ret < 0) {
1178 gnutls_assert();
1179 return ret;
1182 if ((ret =
1183 _gnutls_verify_sig_hdata(state, &peer_cert, &sig,
1184 data_size + HANDSHAKE_HEADER_SIZE)) <
1185 0) {
1186 gnutls_assert();
1187 _gnutls_free_cert(peer_cert);
1188 return ret;
1190 _gnutls_free_cert(peer_cert);
1192 return 0;
1195 #define CERTTYPE_SIZE 3
1196 int _gnutls_gen_cert_server_cert_req(GNUTLS_STATE state, opaque ** data)
1198 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
1199 int size;
1200 opaque *pdata;
1202 /* Now we need to generate the RDN sequence. This is
1203 * already in the CERTIFICATE_CRED structure, to improve
1204 * performance.
1207 cred =
1208 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
1209 NULL);
1210 if (cred == NULL) {
1211 gnutls_assert();
1212 return GNUTLS_E_INSUFICIENT_CRED;
1215 size = CERTTYPE_SIZE + 2; /* 2 for CertificateType + 2 for size of rdn_seq
1218 if (state->security_parameters.cert_type == GNUTLS_CRT_X509)
1219 size += cred->x509_rdn_sequence.size;
1221 (*data) = gnutls_malloc(size);
1222 pdata = (*data);
1224 if (pdata == NULL) {
1225 gnutls_assert();
1226 return GNUTLS_E_MEMORY_ERROR;
1229 pdata[0] = CERTTYPE_SIZE - 1;
1231 pdata[1] = RSA_SIGN;
1232 pdata[2] = DSA_SIGN; /* only these for now */
1233 pdata += CERTTYPE_SIZE;
1235 if (state->security_parameters.cert_type == GNUTLS_CRT_X509) {
1236 _gnutls_write_datum16(pdata, cred->x509_rdn_sequence);
1237 pdata += cred->x509_rdn_sequence.size + 2;
1240 return size;
1244 /* This function will return the appropriate certificate to use. The return
1245 * value depends on the side (client or server).
1247 int _gnutls_find_apr_cert(GNUTLS_STATE state, gnutls_cert ** apr_cert_list,
1248 int *apr_cert_list_length,
1249 gnutls_private_key ** apr_pkey)
1251 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
1252 int ind;
1254 cred =
1255 _gnutls_get_kx_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
1256 NULL);
1258 if (cred == NULL) {
1259 gnutls_assert();
1260 *apr_cert_list = NULL;
1261 *apr_pkey = NULL;
1262 *apr_cert_list_length = 0;
1263 return GNUTLS_E_INSUFICIENT_CRED;
1266 if (state->security_parameters.entity == GNUTLS_SERVER) {
1268 if (cred->ncerts == 0) {
1269 *apr_cert_list = NULL;
1270 *apr_cert_list_length = 0;
1271 *apr_pkey = NULL;
1272 gnutls_assert(); /* this is not allowed */
1273 return GNUTLS_E_INSUFICIENT_CRED;
1274 } else {
1275 /* find_cert_list_index() has been called before.
1277 ind = state->gnutls_internals.selected_cert_index;
1279 if (ind < 0) {
1280 *apr_cert_list = NULL;
1281 *apr_cert_list_length = 0;
1282 *apr_pkey = NULL;
1283 gnutls_assert();
1284 return GNUTLS_E_INSUFICIENT_CRED;
1285 } else {
1286 *apr_cert_list = cred->cert_list[ind];
1287 *apr_cert_list_length =
1288 cred->cert_list_length[ind];
1289 *apr_pkey = &cred->pkey[ind];
1292 } else { /* CLIENT SIDE */
1293 if (cred->ncerts == 0) {
1294 *apr_cert_list = NULL;
1295 *apr_cert_list_length = 0;
1296 *apr_pkey = NULL;
1297 /* it is allowed not to have a certificate
1299 } else {
1300 /* we had already decided which certificate
1301 * to send.
1303 ind = state->gnutls_internals.selected_cert_index;
1305 if (ind < 0) {
1306 *apr_cert_list = NULL;
1307 *apr_cert_list_length = 0;
1308 *apr_pkey = NULL;
1309 } else {
1310 *apr_cert_list = cred->cert_list[ind];
1311 *apr_cert_list_length =
1312 cred->cert_list_length[ind];
1313 *apr_pkey = &cred->pkey[ind];
1319 return 0;
1322 /* finds the most appropriate certificate in the cert list.
1323 * The 'appropriate' is defined by the user.
1324 * (frontend to _gnutls_server_find_cert_index())
1326 const gnutls_cert *_gnutls_server_find_cert(GNUTLS_STATE state,
1327 PKAlgorithm requested_algo)
1329 int i;
1330 const GNUTLS_CERTIFICATE_CREDENTIALS x509_cred;
1332 x509_cred =
1333 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
1334 NULL);
1336 if (x509_cred == NULL)
1337 return NULL;
1339 i = _gnutls_server_find_cert_list_index(state,
1340 x509_cred->cert_list,
1341 x509_cred->ncerts,
1342 requested_algo);
1344 if (i < 0)
1345 return NULL;
1347 return &x509_cred->cert_list[i][0];
1350 /* finds the most appropriate certificate in the cert list.
1351 * The 'appropriate' is defined by the user.
1353 * requested_algo holds the parameters required by the peer (RSA, DSA
1354 * or -1 for any).
1356 int _gnutls_server_find_cert_list_index(GNUTLS_STATE state,
1357 gnutls_cert ** cert_list,
1358 int cert_list_length,
1359 PKAlgorithm requested_algo)
1361 int i, index = -1, j;
1362 const GNUTLS_CERTIFICATE_CREDENTIALS cred;
1363 int my_certs_length;
1364 int *ij_map = NULL;
1366 cred =
1367 _gnutls_get_cred(state->gnutls_key, GNUTLS_CRD_CERTIFICATE,
1368 NULL);
1369 if (cred == NULL) {
1370 gnutls_assert();
1371 return GNUTLS_E_INSUFICIENT_CRED;
1374 index = -1; /* default is use no certificate */
1376 for (i = 0; i < cred->ncerts; i++) {
1377 /* find one compatible certificate */
1378 if (requested_algo == -1 ||
1379 requested_algo ==
1380 cred->cert_list[i][0].subject_pk_algorithm) {
1381 /* if cert type matches */
1382 if (state->security_parameters.cert_type ==
1383 cred->cert_list[i][0].cert_type) {
1384 index = i;
1385 break;
1391 if (state->gnutls_internals.server_cert_callback != NULL && cred->ncerts > 0) { /* use the callback to get certificate */
1392 gnutls_datum *my_certs = NULL;
1394 my_certs =
1395 gnutls_malloc(cred->ncerts * sizeof(gnutls_datum));
1396 if (my_certs == NULL)
1397 goto clear;
1398 my_certs_length = cred->ncerts;
1400 /* put our certificate's issuer and dn into cdn, idn
1402 ij_map = gnutls_malloc(sizeof(int) * cred->ncerts);
1404 j = 0;
1405 for (i = 0; i < cred->ncerts; i++) {
1406 /* Add compatible certificates */
1407 if (requested_algo == -1 ||
1408 requested_algo ==
1409 cred->cert_list[i][0].subject_pk_algorithm) {
1411 /* if cert type matches */
1412 if (state->security_parameters.cert_type ==
1413 cred->cert_list[i][0].cert_type) {
1415 ij_map[j] = i;
1416 my_certs[j++] =
1417 cred->cert_list[i][0].raw;
1421 my_certs_length = j;
1423 index =
1424 state->gnutls_internals.server_cert_callback(state,
1425 my_certs,
1426 my_certs_length);
1428 index = ij_map[index];
1430 clear:
1431 gnutls_free(my_certs);
1432 gnutls_free(ij_map);
1435 /* store the index for future use, in the handshake.
1436 * (This will allow not calling this callback again.)
1438 state->gnutls_internals.selected_cert_index = index;
1439 return index;