diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-09-14 08:04:39 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-09-14 08:04:39 +0000 |
commit | 98dd96368dbc6a79414f359afadce10cf2481f36 (patch) | |
tree | c62dc3fe035727ca48a6dc5ba6647377c369dda0 | |
parent | 192ba23c68c1a61776543ddc62c6d0d3c7b61d5a (diff) | |
download | gnutls-98dd96368dbc6a79414f359afadce10cf2481f36.tar.gz |
Client certificate callback has been improved
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | doc/tex/ex3.tex | 6 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/auth_rsa.c | 91 | ||||
-rw-r--r-- | lib/auth_x509.c | 4 | ||||
-rw-r--r-- | lib/auth_x509.h | 4 | ||||
-rw-r--r-- | lib/gnutls.h.in | 2 | ||||
-rw-r--r-- | lib/gnutls_cert.c | 661 | ||||
-rw-r--r-- | lib/gnutls_cert.h | 7 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 4 | ||||
-rw-r--r-- | lib/gnutls_int.h | 4 | ||||
-rw-r--r-- | lib/gnutls_ui.c | 12 | ||||
-rw-r--r-- | lib/gnutls_ui.h | 10 | ||||
-rw-r--r-- | lib/x509_extensions.c | 14 | ||||
-rw-r--r-- | src/cli.c | 35 | ||||
-rw-r--r-- | src/serv.c | 6 |
16 files changed, 558 insertions, 308 deletions
@@ -1,7 +1,5 @@ -Version ?.?.? +Version 0.2.3 - Memory optimizations in gnutls_recv() - -Version 0.2.3 (21/08/2001) - Fixed several memory leaks - Added ability to specify callback for x509 client certificate selection diff --git a/doc/tex/ex3.tex b/doc/tex/ex3.tex index 4e02731a0e..243e45f564 100644 --- a/doc/tex/ex3.tex +++ b/doc/tex/ex3.tex @@ -7,7 +7,8 @@ PRINTX( "L:", X->locality_name); \ PRINTX( "S:", X->state_or_province_name); \ PRINTX( "C:", X->country); \ - PRINTX( "SAN:", gnutls_x509pki_client_get_subject_alt_name(x509_info)) + PRINTX( "E:", X->email); \ + PRINTX( "SAN:", gnutls_x509pki_client_get_subject_dns_name(x509_info)) int print_info(GNUTLS_STATE state) { @@ -35,6 +36,9 @@ int print_info(GNUTLS_STATE state) case GNUTLS_CERT_TRUSTED: printf("- Peer's X509 Certificate was verified\n"); break; + case GNUTLS_CERT_NONE: + printf("- Peer did not send any X509 Certificate.\n"); + break; case GNUTLS_CERT_INVALID: default: printf("- Peer's X509 Certificate was invalid\n"); diff --git a/lib/Makefile.am b/lib/Makefile.am index d7a4d7b6cd..50d5c6eb03 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -49,7 +49,7 @@ pkcs1_asn1_tab.c: pkcs1.asn gnutls-api.tex: $(COBJECTS) @echo "\\newpage" > gnutls-api.tex @echo "\\section{Function Reference}" >> gnutls-api.tex - for i in $(COBJECTS); \ + @for i in $(COBJECTS); \ do echo -n "Creating documentation for file $$i... " && ../doc/scripts/gdoc -tex $$i >> gnutls-api.tex \ && echo "ok"; \ done diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c index 52dc52d7a4..a5c305520a 100644 --- a/lib/auth_rsa.c +++ b/lib/auth_rsa.c @@ -459,11 +459,15 @@ int proc_rsa_server_certificate(GNUTLS_STATE state, opaque * data, int data_size size = READuint24(p); p += 3; + info = state->gnutls_key->auth_info; + info->peer_certificate_status = GNUTLS_CERT_INVALID; + if (size == 0) { gnutls_assert(); + /* no certificate was sended */ + info->peer_certificate_status = GNUTLS_CERT_NONE; return GNUTLS_E_NO_CERTIFICATE_FOUND; } - info = state->gnutls_key->auth_info; i = dsize; len = READuint24(p); @@ -600,6 +604,8 @@ int gen_rsa_client_kx(GNUTLS_STATE state, opaque ** data) } +/* Returns the issuer's Distinguished name in odn, of the certificate specified in cert. + */ int _gnutls_find_dn( gnutls_datum* odn, gnutls_cert* cert) { node_asn* dn; int len, result; @@ -637,22 +643,56 @@ int start, end; return 0; } +/* Gets the Distinguished name in idn, and returns a gnutls_DN structure. + */ +int _gnutls_dn2gnutlsdn( gnutls_DN* rdn, gnutls_datum* idn) { +node_asn* dn; +int result; + + if ((result=asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Name", &dn, "dn")) != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_get_der( dn, idn->data, idn->size); + if (result != ASN_OK) { + /* couldn't decode DER */ + gnutls_assert(); + asn1_delete_structure( dn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + result = _gnutls_get_name_type( dn, "dn", rdn); + asn1_delete_structure( dn); + + if (result < 0) { + /* couldn't decode DER */ + gnutls_assert(); + return result; + } + + return 0; +} + + /* Finds the appropriate certificate depending on the cA Distinguished name * advertized by the server. If none matches then returns -1 as index. */ -static int _gnutls_find_acceptable_client_cert( const X509PKI_CREDENTIALS cred, const opaque* data, - int data_size, int *ind) { +static int _gnutls_find_acceptable_client_cert( const X509PKI_CREDENTIALS cred, opaque* _data, + int _data_size, int *ind) { int result, size; int indx = -1; int i, j, try=0; gnutls_datum odn; +opaque* data = _data; +int data_size = _data_size; if (cred->client_cert_callback!=NULL) { /* if try>=0 then the client wants automatic * choose of certificate, otherwise (-1), he * will be prompted to choose one. */ - try = cred->client_cert_callback( NULL, NULL, 0); + try = cred->client_cert_callback( NULL, NULL, 0, NULL, 0); } if (try>=0) @@ -660,6 +700,7 @@ gnutls_datum odn; DECR_LEN(data_size, 2); size = READuint16(data); + DECR_LEN(data_size, size); data += 2; for(i=0;i<cred->ncerts;i++) { @@ -671,7 +712,7 @@ gnutls_datum odn; } if ( odn.size != size) continue; - + if (memcmp( odn.data, data, size) == 0 ) { @@ -698,6 +739,9 @@ gnutls_datum odn; if (indx==-1 && cred->client_cert_callback!=NULL && cred->ncerts > 0) {/* use a callback to get certificate */ gnutls_DN *cdn=NULL; gnutls_DN *idn=NULL; + gnutls_DN *req_dn=NULL; + gnutls_datum tmp; + int count; cdn = gnutls_malloc( cred->ncerts* sizeof(gnutls_DN)); if (cdn==NULL) goto clear; @@ -705,14 +749,45 @@ gnutls_datum odn; idn = gnutls_malloc( cred->ncerts* sizeof(gnutls_DN)); if (idn==NULL) goto clear; + /* put the requested DNs to req_dn + */ + data = _data; + data_size = _data_size; + count = 0; /* holds the number of given CA's DN */ + do { + data_size-=2; + if (data_size<=0) goto clear; + size = READuint16(data); + data_size-=size; + if (data_size<0) goto clear; + + + data += 2; + + req_dn = gnutls_realloc_fast( req_dn, (count+1)*sizeof(gnutls_DN)); + if (req_dn==NULL) goto clear; + + tmp.data = data; + tmp.size = size; + if (_gnutls_dn2gnutlsdn( &req_dn[count], &tmp)==0) + count++; /* otherwise we have failed */ + data+=size; + + if (data_size==0) break; + + } while(1); + + /* put our certificate's issuer and dn into cdn, idn + */ for(i=0;i<cred->ncerts;i++) { memcpy( &cdn[i], &cred->cert_list[i][0].cert_info, sizeof(gnutls_DN)); memcpy( &idn[i], &cred->cert_list[i][0].issuer_info, sizeof(gnutls_DN)); } - indx = cred->client_cert_callback( cdn, idn, cred->ncerts); - + indx = cred->client_cert_callback( cdn, idn, cred->ncerts, req_dn, count); + clear: gnutls_free(cdn); + gnutls_free(req_dn); gnutls_free(idn); } *ind = indx; @@ -749,6 +824,8 @@ int proc_rsa_cert_req(GNUTLS_STATE state, opaque * data, int data_size) size = p[0]; p += 1; + /* FIXME: Add support for DSS certificates too + */ found = 0; for (i = 0; i < size; i++, p++) { DECR_LEN(dsize, 1); diff --git a/lib/auth_x509.c b/lib/auth_x509.c index a90615990a..1e95ba17e8 100644 --- a/lib/auth_x509.c +++ b/lib/auth_x509.c @@ -37,8 +37,8 @@ void _gnutls_copy_x509_client_auth_info( X509PKI_CLIENT_AUTH_INFO info, gnutls_c info->peer_certificate_version = cert->version; - if ( cert->subjectAltName[0]!=0) - strcpy( info->subjectAltName, cert->subjectAltName); + if ( cert->subjectAltDNSName[0]!=0) + strcpy( info->subjectAltDNSName, cert->subjectAltDNSName); info->keyUsage = cert->keyUsage; diff --git a/lib/auth_x509.h b/lib/auth_x509.h index e95552e58a..d62c98e76a 100644 --- a/lib/auth_x509.h +++ b/lib/auth_x509.h @@ -30,7 +30,7 @@ typedef struct { /* this is a callback function to call if no appropriate * client certificates were found. */ - int (*client_cert_callback)(gnutls_DN*, gnutls_DN*, int); + int (*client_cert_callback)(gnutls_DN*, gnutls_DN*, int, gnutls_DN*, int); } X509PKI_CREDENTIALS_INT; /* typedef X509PKI_CREDENTIALS_INT * X509PKI_CREDENTIALS; */ @@ -43,7 +43,7 @@ typedef struct X509PKI_CLIENT_AUTH_INFO_INT { int peer_certificate_version; time_t peer_certificate_activation_time; time_t peer_certificate_expiration_time; - char subjectAltName[X509_CN_SIZE]; + char subjectAltDNSName[X509_CN_SIZE]; unsigned char keyUsage; int certificate_requested; } *X509PKI_CLIENT_AUTH_INFO; diff --git a/lib/gnutls.h.in b/lib/gnutls.h.in index cebb4da2e3..5aba9aa750 100644 --- a/lib/gnutls.h.in +++ b/lib/gnutls.h.in @@ -50,7 +50,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1 } AlertDescription; -typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus; +typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID, GNUTLS_CERT_NONE } CertificateStatus; typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest; typedef enum CloseRequest { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } CloseRequest; diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 5d62ca240d..09e29c1734 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -70,23 +70,25 @@ PKAlgorithm _gnutls_map_pk_get_pk(KXAlgorithm kx_algorithm) } #define GNUTLS_FREE(x) if(x!=NULL) gnutls_free(x) -void gnutls_free_cert( gnutls_cert cert) { -int n,i; +void gnutls_free_cert(gnutls_cert cert) +{ + int n, i; - switch( cert.subject_pk_algorithm) { + switch (cert.subject_pk_algorithm) { case GNUTLS_PK_RSA: - n = 2;/* the number of parameters in MPI* */ + n = 2; /* the number of parameters in MPI* */ break; default: - n=0; + n = 0; } - - for (i=0;i<n;i++) { - _gnutls_mpi_release( &cert.params[i]); + + for (i = 0; i < n; i++) { + _gnutls_mpi_release(&cert.params[i]); } - if (cert.params!=NULL) gnutls_free( cert.params); - - gnutls_free_datum( &cert.raw); + if (cert.params != NULL) + gnutls_free(cert.params); + + gnutls_free_datum(&cert.raw); return; } @@ -99,28 +101,33 @@ int n,i; * this helper function is provided in order to free (deallocate) * the structure. **/ -void gnutls_free_x509_sc( X509PKI_CREDENTIALS sc) { -int i,j; +void gnutls_free_x509_sc(X509PKI_CREDENTIALS sc) +{ + int i, j; - for (i=0;i<sc->ncerts;i++) { - for (j=0;j<sc->cert_list_length[i];j++) { - gnutls_free_cert( sc->cert_list[i][j]); + for (i = 0; i < sc->ncerts; i++) { + for (j = 0; j < sc->cert_list_length[i]; j++) { + gnutls_free_cert(sc->cert_list[i][j]); } - gnutls_free( sc->cert_list[i]); + gnutls_free(sc->cert_list[i]); } - if (sc->cert_list_length!=NULL) gnutls_free( sc->cert_list_length); - if (sc->cert_list!=NULL) gnutls_free( sc->cert_list ); + if (sc->cert_list_length != NULL) + gnutls_free(sc->cert_list_length); + if (sc->cert_list != NULL) + gnutls_free(sc->cert_list); - for (j=0;j<sc->ncas;j++) { - gnutls_free_cert( sc->ca_list[j]); + for (j = 0; j < sc->ncas; j++) { + gnutls_free_cert(sc->ca_list[j]); } - if (sc->ca_list!=NULL) gnutls_free( sc->ca_list); + if (sc->ca_list != NULL) + gnutls_free(sc->ca_list); - for (i=0;i<sc->ncerts;i++) { - _gnutls_free_private_key( sc->pkey[i]); + for (i = 0; i < sc->ncerts; i++) { + _gnutls_free_private_key(sc->pkey[i]); } - if(sc->pkey!=NULL) gnutls_free(sc->pkey); + if (sc->pkey != NULL) + gnutls_free(sc->pkey); gnutls_free(sc); } @@ -130,14 +137,15 @@ int i,j; /* Reads a base64 encoded certificate file */ -static int read_cert_file( X509PKI_CREDENTIALS res, char* certfile) { -int siz, i, siz2; -opaque* b64; -char x[MAX_FILE_SIZE]; -char* ptr; -FILE* fd1; -gnutls_datum tmp; -int ret; +static int read_cert_file(X509PKI_CREDENTIALS res, char *certfile) +{ + int siz, i, siz2; + opaque *b64; + char x[MAX_FILE_SIZE]; + char *ptr; + FILE *fd1; + gnutls_datum tmp; + int ret; fd1 = fopen(certfile, "r"); if (fd1 == NULL) @@ -145,26 +153,29 @@ int ret; siz = fread(x, 1, sizeof(x), fd1); fclose(fd1); - + ptr = x; - i=1; + i = 1; res->cert_list[res->ncerts] = NULL; do { siz2 = _gnutls_fbase64_decode(ptr, siz, &b64); - siz-=siz2; /* FIXME: this is not enough - */ + siz -= siz2; /* FIXME: this is not enough + */ if (siz2 < 0) { gnutls_assert(); gnutls_free(b64); return GNUTLS_E_PARSING_ERROR; } - ptr = strstr( ptr, CERT_SEP)+1; + ptr = strstr(ptr, CERT_SEP) + 1; res->cert_list[res->ncerts] = - (gnutls_cert *) gnutls_realloc( res->cert_list[res->ncerts], i * sizeof(gnutls_cert)); + (gnutls_cert *) gnutls_realloc(res-> + cert_list[res->ncerts], + i * + sizeof(gnutls_cert)); if (res->cert_list[res->ncerts] == NULL) { gnutls_assert(); @@ -173,23 +184,26 @@ int ret; } /* set defaults to zero */ - memset( &res->cert_list[res->ncerts][i-1], 0, sizeof(gnutls_cert)); - + memset(&res->cert_list[res->ncerts][i - 1], 0, + sizeof(gnutls_cert)); + tmp.data = b64; tmp.size = siz2; if ((ret = - _gnutls_cert2gnutlsCert(&res->cert_list[res->ncerts][i-1], tmp)) < 0) { - gnutls_free( b64); + _gnutls_cert2gnutlsCert(&res-> + cert_list[res->ncerts][i - 1], + tmp)) < 0) { + gnutls_free(b64); gnutls_assert(); return ret; } - gnutls_free( b64); + gnutls_free(b64); i++; - } while( (ptr=strstr( ptr, CERT_SEP))!=NULL); + } while ((ptr = strstr(ptr, CERT_SEP)) != NULL); + + res->cert_list_length[res->ncerts] = i - 1; - res->cert_list_length[res->ncerts] = i-1; - /* WE DO NOT CATCH OVERRUNS in gnutls_set_x509_key(). * This function should be called as many times as specified * in allocate_x509_sc(). @@ -202,77 +216,82 @@ int ret; /* Reads a base64 encoded CA file (file contains multiple certificate * authorities). This is to be called once. */ -static int read_ca_file( X509PKI_CREDENTIALS res, char* cafile) { -int siz, siz2, i; -opaque* b64; -char x[MAX_FILE_SIZE]; -char* ptr; -FILE* fd1; -int ret; -gnutls_datum tmp; +static int read_ca_file(X509PKI_CREDENTIALS res, char *cafile) +{ + int siz, siz2, i; + opaque *b64; + char x[MAX_FILE_SIZE]; + char *ptr; + FILE *fd1; + int ret; + gnutls_datum tmp; fd1 = fopen(cafile, "r"); if (fd1 == NULL) { gnutls_assert(); return GNUTLS_E_UNKNOWN_ERROR; } - + siz = fread(x, 1, sizeof(x), fd1); fclose(fd1); ptr = x; - res->ncas=0; - i=1; + res->ncas = 0; + i = 1; res->ca_list = NULL; do { siz2 = _gnutls_fbase64_decode(ptr, siz, &b64); - siz-=siz2; /* FIXME: this is not enough - */ + siz -= siz2; /* FIXME: this is not enough + */ if (siz2 < 0) { gnutls_assert(); gnutls_free(b64); return GNUTLS_E_PARSING_ERROR; } - ptr = strstr( ptr, CERT_SEP)+1; + ptr = strstr(ptr, CERT_SEP) + 1; res->ca_list = - (gnutls_cert *) gnutls_realloc( res->ca_list, i * sizeof(gnutls_cert)); + (gnutls_cert *) gnutls_realloc(res->ca_list, + i * + sizeof(gnutls_cert)); if (res->ca_list == NULL) { gnutls_assert(); gnutls_free(b64); return GNUTLS_E_MEMORY_ERROR; } - memset( &res->ca_list[i-1], 0, sizeof(gnutls_cert)); - + memset(&res->ca_list[i - 1], 0, sizeof(gnutls_cert)); + tmp.data = b64; tmp.size = siz2; if ((ret = - _gnutls_cert2gnutlsCert(&res->ca_list[i-1], tmp)) < 0) { + _gnutls_cert2gnutlsCert(&res->ca_list[i - 1], + tmp)) < 0) { gnutls_assert(); gnutls_free(b64); return ret; } - gnutls_free( b64); + gnutls_free(b64); i++; - } while( (ptr=strstr( ptr, CERT_SEP))!=NULL); + } while ((ptr = strstr(ptr, CERT_SEP)) != NULL); - res->ncas = i-1; + res->ncas = i - 1; return 0; } /* Reads a PEM encoded PKCS-1 RSA private key file */ -static int read_key_file( X509PKI_CREDENTIALS res, char* keyfile) { -int siz, ret; -opaque* b64; -gnutls_datum tmp; -char x[MAX_FILE_SIZE]; -FILE* fd2; +static int read_key_file(X509PKI_CREDENTIALS res, char *keyfile) +{ + int siz, ret; + opaque *b64; + gnutls_datum tmp; + char x[MAX_FILE_SIZE]; + FILE *fd2; fd2 = fopen(keyfile, "r"); if (fd2 == NULL) @@ -293,11 +312,13 @@ FILE* fd2; tmp.data = b64; tmp.size = siz; - if ( (ret =_gnutls_pkcs1key2gnutlsKey(&res->pkey[res->ncerts], tmp)) < 0) { + if ((ret = + _gnutls_pkcs1key2gnutlsKey(&res->pkey[res->ncerts], + tmp)) < 0) { gnutls_assert(); gnutls_free(b64); return ret; - } + } gnutls_free(b64); @@ -315,35 +336,39 @@ FILE* fd2; * this helper function is provided in order to allocate * the structure. **/ -int gnutls_allocate_x509_sc(X509PKI_CREDENTIALS* res, int ncerts) +int gnutls_allocate_x509_sc(X509PKI_CREDENTIALS * res, int ncerts) { - *res = gnutls_calloc( 1, sizeof( X509PKI_CREDENTIALS_INT)); + *res = gnutls_calloc(1, sizeof(X509PKI_CREDENTIALS_INT)); - if (*res==NULL) return GNUTLS_E_MEMORY_ERROR; + if (*res == NULL) + return GNUTLS_E_MEMORY_ERROR; - (*res)->ncerts=0; /* this is right - set_key() increments it */ + (*res)->ncerts = 0; /* this is right - set_key() increments it */ if (ncerts > 0) { (*res)->cert_list = - (gnutls_cert **) gnutls_malloc( ncerts * sizeof(gnutls_cert *)); + (gnutls_cert **) gnutls_malloc(ncerts * + sizeof(gnutls_cert *)); - if ( (*res)->cert_list == NULL) { + if ((*res)->cert_list == NULL) { gnutls_free(*res); return GNUTLS_E_MEMORY_ERROR; } - (*res)->cert_list_length = (int *) gnutls_malloc( ncerts * sizeof(int *)); - if ( (*res)->cert_list_length == NULL) { - gnutls_free( *res); - gnutls_free( (*res)->cert_list); + (*res)->cert_list_length = + (int *) gnutls_malloc(ncerts * sizeof(int *)); + if ((*res)->cert_list_length == NULL) { + gnutls_free(*res); + gnutls_free((*res)->cert_list); return GNUTLS_E_MEMORY_ERROR; } - (*res)->pkey = gnutls_malloc( ncerts * sizeof(gnutls_private_key)); - if ( (*res)->pkey == NULL) { - gnutls_free( *res); - gnutls_free( (*res)->cert_list); - gnutls_free( (*res)->cert_list_length); + (*res)->pkey = + gnutls_malloc(ncerts * sizeof(gnutls_private_key)); + if ((*res)->pkey == NULL) { + gnutls_free(*res); + gnutls_free((*res)->cert_list); + gnutls_free((*res)->cert_list_length); return GNUTLS_E_MEMORY_ERROR; } @@ -363,16 +388,17 @@ int gnutls_allocate_x509_sc(X509PKI_CREDENTIALS* res, int ncerts) * more than once (in case multiple keys/certificates exist for the * server) **/ -int gnutls_set_x509_key(X509PKI_CREDENTIALS res, char* CERTFILE, char *KEYFILE) +int gnutls_set_x509_key(X509PKI_CREDENTIALS res, char *CERTFILE, + char *KEYFILE) { -int ret; + int ret; /* this should be first */ - if ( (ret=read_key_file( res, KEYFILE)) < 0) + if ((ret = read_key_file(res, KEYFILE)) < 0) return ret; - if ( (ret=read_cert_file( res, CERTFILE)) < 0) + if ((ret = read_cert_file(res, CERTFILE)) < 0) return ret; return 0; @@ -387,11 +413,12 @@ int ret; * This function sets the trusted CAs in order to verify client * certificates. **/ -int gnutls_set_x509_trust(X509PKI_CREDENTIALS res, char* CAFILE, char* CRLFILE) +int gnutls_set_x509_trust(X509PKI_CREDENTIALS res, char *CAFILE, + char *CRLFILE) { -int ret; + int ret; - if ( (ret=read_ca_file( res, CAFILE)) < 0) + if ((ret = read_ca_file(res, CAFILE)) < 0) return ret; return 0; @@ -405,12 +432,13 @@ static int _read_rsa_params(opaque * der, int dersize, MPI ** params) node_asn *spk; if (asn1_create_structure - ( _gnutls_get_pkcs(), "PKCS-1.RSAPublicKey", &spk, "rsa_public_key") != ASN_OK) { + (_gnutls_get_pkcs(), "PKCS-1.RSAPublicKey", &spk, + "rsa_public_key") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } - result = asn1_get_der ( spk, der, dersize); + result = asn1_get_der(spk, der, dersize); if (result != ASN_OK) { gnutls_assert(); @@ -437,7 +465,9 @@ static int _read_rsa_params(opaque * der, int dersize, MPI ** params) } len = sizeof(str) - 1; - result = asn1_read_value(spk, "rsa_public_key.publicExponent", str, &len); + result = + asn1_read_value(spk, "rsa_public_key.publicExponent", str, + &len); if (result != ASN_OK) { gnutls_assert(); _gnutls_mpi_release(&(*params)[0]); @@ -461,70 +491,106 @@ static int _read_rsa_params(opaque * der, int dersize, MPI ** params) } -/* res is not malloced - */ -#define _READ( str, OID, ANAME, NAME, res) \ - if(strcmp(str, OID)==0){ \ - strcpy( str, "PKIX1Implicit88."); \ - strcat( str, ANAME); \ - strcpy( name2, "temp-structure-"); \ - strcat( name2, NAME); \ - if ( (result = asn1_create_structure( _gnutls_get_pkix(), str, &tmpasn, name2)) != ASN_OK) { \ - gnutls_assert(); \ - return GNUTLS_E_ASN1_ERROR; \ - } \ - len = sizeof(str) - 1; \ - if ( (result=asn1_read_value( rasn, name3, str,&len)) != ASN_OK) { \ - asn1_delete_structure( tmpasn); \ - continue; \ - } \ - if ( (result=asn1_get_der( tmpasn, str, len)) != ASN_OK) { \ - asn1_delete_structure( tmpasn); \ - continue; \ - } \ - strcpy( name3,name2); \ - len = sizeof(str) - 1; \ - if ( (result=asn1_read_value( tmpasn, name3, str, &len)) != ASN_OK) { /* CHOICE */ \ - asn1_delete_structure( tmpasn); \ - continue; \ - } \ - str[len] = 0; \ - strcat( name3, "."); \ - strcat( name3, str); \ - len = sizeof(str) - 1; \ - if ( (result=asn1_read_value( tmpasn, name3, str,&len)) != ASN_OK) { \ - asn1_delete_structure( tmpasn); \ - continue; \ - } \ - str[len]=0; \ - if (strlen(str) < sizeof(res)) strcpy( res, str); \ - asn1_delete_structure( tmpasn); \ - } +#define _READ(a, aa, b, c, d, e, res, f) \ + result = _IREAD(a, aa, b, c, d, e, res, sizeof(res), f); \ + if (result<0) return result; \ + if (result==1) continue +int _IREAD(node_asn * rasn, char* name3, char *rstr, char *OID, char *ANAME, char *TYPE, + char *res, int res_size, int CHOICE) +{ + char name2[256]; + int result, len; + char str[1024]; + node_asn *tmpasn; + + if (strcmp(rstr, OID) == 0) { + + strcpy(str, "PKIX1Implicit88."); + strcat(str, ANAME); + strcpy(name2, "temp-structure-"); + strcat(name2, TYPE); + + if ((result = + asn1_create_structure(_gnutls_get_pkix(), str, + &tmpasn, name2)) != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + len = sizeof(str) - 1; + if ((result = + asn1_read_value(rasn, name3, str, &len)) != ASN_OK) { + asn1_delete_structure(tmpasn); + return 1; + } + + if ((result = asn1_get_der(tmpasn, str, len)) != ASN_OK) { + asn1_delete_structure(tmpasn); + return 1; + } + strcpy(name3, name2); + + len = sizeof(str) - 1; + if ((result = asn1_read_value(tmpasn, name3, str, &len)) != ASN_OK) { /* CHOICE */ + asn1_delete_structure(tmpasn); + return 1; + } + + if (CHOICE == 0) { + str[len] = 0; + strcpy(res, str); + asn1_delete_structure(tmpasn); + } else { /* CHOICE */ + str[len] = 0; + strcat(name3, "."); + strcat(name3, str); + len = sizeof(str) - 1; + + if ((result = + asn1_read_value(tmpasn, name3, str, + &len)) != ASN_OK) { + asn1_delete_structure(tmpasn); + return 1; + } + str[len] = 0; + if (strlen(str) < res_size) + strcpy(res, str); + asn1_delete_structure(tmpasn); + } + } + return 0; +} + /* this function will convert up to 3 digit * numbers to characters. */ -void _gnutls_int2str(int k, char* data) { - if (k > 999) data[0] = 0; - else sprintf( data, "%d", k); +void _gnutls_int2str(int k, char *data) +{ + if (k > 999) + data[0] = 0; + else + sprintf(data, "%d", k); } /* This function will attempt to read a Name * ASN.1 structure. (Taken from Fabio's samples!) * * FIXME: These functions need carefull auditing + * (they're complex enough) * --nmav */ -static int _get_Name_type( node_asn *rasn, char *root, gnutls_DN * dn) +int _gnutls_get_name_type(node_asn * rasn, char *root, gnutls_DN * dn) { int k, k2, result, len; - char name[128], str[1024], name2[128], counter[MAX_INT_DIGITS], name3[128]; + char name[128], str[1024], name2[128], counter[MAX_INT_DIGITS], + name3[128]; k = 0; do { k++; - + strcpy(name, root); strcat(name, ".rdnSequence.?"); _gnutls_int2str(k, counter); @@ -532,11 +598,16 @@ static int _get_Name_type( node_asn *rasn, char *root, gnutls_DN * dn) len = sizeof(str) - 1; - result = asn1_read_value( rasn, name, str, &len); - + result = asn1_read_value(rasn, name, str, &len); + /* move to next */ - if (result==ASN_ELEMENT_NOT_FOUND) break; + if (result == ASN_ELEMENT_NOT_FOUND) + break; + if (result != ASN_VALUE_NOT_FOUND) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } k2 = 0; do { @@ -548,68 +619,85 @@ static int _get_Name_type( node_asn *rasn, char *root, gnutls_DN * dn) strcat(name2, counter); len = sizeof(str) - 1; - result = asn1_read_value( rasn, name2, str, &len); + result = asn1_read_value(rasn, name2, str, &len); - if (result==ASN_ELEMENT_NOT_FOUND) break; + if (result == ASN_ELEMENT_NOT_FOUND) + break; + if (result != ASN_VALUE_NOT_FOUND) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } strcpy(name3, name2); strcat(name3, ".type"); - + len = sizeof(str) - 1; - result = asn1_read_value( rasn, name3, str, &len); - - if (result==ASN_ELEMENT_NOT_FOUND) break; - else - if (result != ASN_OK) { - gnutls_assert(); - return GNUTLS_E_ASN1_PARSING_ERROR; - } + result = asn1_read_value(rasn, name3, str, &len); + + if (result == ASN_ELEMENT_NOT_FOUND) + break; + else if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + strcpy(name3, name2); strcat(name3, ".value"); if (result == ASN_OK) { - node_asn *tmpasn; #ifdef DEBUG # warning " FIX COUNTRY HERE" #endif - _READ(str, "2 5 4 6", "X520OrganizationName", - "countryName", dn->country); - _READ(str, "2 5 4 10", "X520OrganizationName", - "OrganizationName", dn->organization); - _READ(str, "2 5 4 11", "X520OrganizationalUnitName", - "OrganizationalUnitName", dn->organizational_unit_name); - _READ(str, "2 5 4 3", "X520CommonName", - "CommonName", dn->common_name); - _READ(str, "2 5 4 7", "X520LocalityName", - "LocalityName", dn->locality_name); - _READ(str, "2 5 4 8", "X520StateOrProvinceName", - "StateOrProvinceName", dn->state_or_province_name); + _READ(rasn, name3, str, "2 5 4 6", + "X520OrganizationName", + "countryName", dn->country, 1); + _READ(rasn, name3, str, "2 5 4 10", + "X520OrganizationName", + "OrganizationName", dn->organization, + 1); + _READ(rasn, name3, str, "2 5 4 11", + "X520OrganizationalUnitName", + "OrganizationalUnitName", + dn->organizational_unit_name, 1); + _READ(rasn, name3, str, "2 5 4 3", + "X520CommonName", "CommonName", + dn->common_name, 1); + _READ(rasn, name3, str, "2 5 4 7", + "X520LocalityName", "LocalityName", + dn->locality_name, 1); + _READ(rasn, name3, str, "2 5 4 8", + "X520StateOrProvinceName", + "StateOrProvinceName", + dn->state_or_province_name, 1); + _READ(rasn, name3, str, "1 2 840 113549 1 9 1", + "Pkcs9email", "emailAddress", + dn->email, 0); } } while (1); } while (1); - if (result==ASN_ELEMENT_NOT_FOUND) + if (result == ASN_ELEMENT_NOT_FOUND) return 0; - else + else return GNUTLS_E_ASN1_PARSING_ERROR; } #define MAX_TIME 1024 -static time_t _gnutls_get_time( node_asn* c2, char* root, char* when) { -opaque ttime[MAX_TIME]; -char name[1024]; -time_t ctime; -int len, result; +static time_t _gnutls_get_time(node_asn * c2, char *root, char *when) +{ + opaque ttime[MAX_TIME]; + char name[1024]; + time_t ctime; + int len, result; strcpy(name, root); strcat(name, ".tbsCertificate.validity."); strcat(name, when); - + len = sizeof(ttime) - 1; - if ((result = - asn1_read_value(c2, name, ttime, &len)) < 0) { + if ((result = asn1_read_value(c2, name, ttime, &len)) < 0) { gnutls_assert(); return (time_t) (-1); } @@ -623,8 +711,7 @@ int len, result; strcat(name, when); strcat(name, ".generalTime"); len = sizeof(ttime) - 1; - result = - asn1_read_value(c2, name, ttime, &len); + result = asn1_read_value(c2, name, ttime, &len); if (result == ASN_OK) ctime = _gnutls_generalTime2gtime(ttime); } else { /* UTCTIME */ @@ -633,34 +720,33 @@ int len, result; strcat(name, when); strcat(name, ".utcTime"); len = sizeof(ttime) - 1; - result = - asn1_read_value(c2, name, ttime, &len); + result = asn1_read_value(c2, name, ttime, &len); if (result == ASN_OK) ctime = _gnutls_utcTime2gtime(ttime); } - if (result!=ASN_OK) { + if (result != ASN_OK) { gnutls_assert(); return (time_t) (-1); } return ctime; } -static int _gnutls_get_version( node_asn* c2, char* root) { -opaque gversion[5]; -char name[1024]; -int len, result; +static int _gnutls_get_version(node_asn * c2, char *root) +{ + opaque gversion[5]; + char name[1024]; + int len, result; strcpy(name, root); strcat(name, ".tbsCertificate.version"); - + len = sizeof(gversion) - 1; - if ((result = - asn1_read_value(c2, name, gversion, &len)) < 0) { + if ((result = asn1_read_value(c2, name, gversion, &len)) < 0) { gnutls_assert(); return (-1); } - return (int) gversion[0]+1; + return (int) gversion[0] + 1; } int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) @@ -671,19 +757,21 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) int len = sizeof(str); gCert->valid = 1; - - if (asn1_create_structure( _gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2, "certificate2") + + if (asn1_create_structure + (_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &c2, + "certificate2") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } - result = asn1_get_der( c2, derCert.data, derCert.size); + result = asn1_get_der(c2, derCert.data, derCert.size); if (result != ASN_OK) { /* couldn't decode DER */ #ifdef DEBUG - _gnutls_log( "Decoding error %d\n", result); -#endif + _gnutls_log("Decoding error %d\n", result); +#endif gnutls_assert(); return GNUTLS_E_ASN1_PARSING_ERROR; } @@ -691,7 +779,8 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) len = sizeof(str) - 1; result = asn1_read_value - (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", + (c2, + "certificate2.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm", str, &len); if (result != ASN_OK) { @@ -709,7 +798,8 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) len = sizeof(str) - 1; result = asn1_read_value - (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", + (c2, + "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", str, &len); if (result != ASN_OK) { @@ -729,70 +819,77 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) */ gnutls_assert(); #ifdef DEBUG -_gnutls_log( "ALGORITHM: %s\n", str); -return GNUTLS_E_UNIMPLEMENTED_FEATURE; + _gnutls_log("ALGORITHM: %s\n", str); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; #endif gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN; gCert->params = NULL; - + } - len = sizeof( gCert->signature); + len = sizeof(gCert->signature); result = asn1_read_value - (c2, "certificate2.signature", - gCert->signature, &len); + (c2, "certificate2.signature", gCert->signature, &len); - if ((len % 8) !=0) { + if ((len % 8) != 0) { gnutls_assert(); asn1_delete_structure(c2); - return GNUTLS_E_UNIMPLEMENTED_FEATURE; + return GNUTLS_E_UNIMPLEMENTED_FEATURE; } - len /= 8; /* convert to bytes */ + len /= 8; /* convert to bytes */ gCert->signature_size = len; - memset( &gCert->cert_info, 0, sizeof(gCert->cert_info)); - memset( &gCert->issuer_info, 0, sizeof(gCert->issuer_info)); + memset(&gCert->cert_info, 0, sizeof(gCert->cert_info)); + memset(&gCert->issuer_info, 0, sizeof(gCert->issuer_info)); if ((result = - _get_Name_type( c2, "certificate2.tbsCertificate.subject", &gCert->cert_info)) < 0) { + _gnutls_get_name_type(c2, + "certificate2.tbsCertificate.subject", + &gCert->cert_info)) < 0) { gnutls_assert(); asn1_delete_structure(c2); return result; } - memset( &gCert->subjectAltName, 0, sizeof(gCert->subjectAltName)); + memset(&gCert->subjectAltDNSName, 0, sizeof(gCert->subjectAltDNSName)); if ((result = - _gnutls_get_ext_type( c2, "certificate2.tbsCertificate.extensions", gCert)) < 0) { + _gnutls_get_ext_type(c2, + "certificate2.tbsCertificate.extensions", + gCert)) < 0) { gnutls_assert(); asn1_delete_structure(c2); return result; } if ((result = - _get_Name_type( c2, "certificate2.tbsCertificate.issuer", &gCert->issuer_info)) < 0) { + _gnutls_get_name_type(c2, + "certificate2.tbsCertificate.issuer", + &gCert->issuer_info)) < 0) { gnutls_assert(); asn1_delete_structure(c2); return result; } - gCert->expiration_time = _gnutls_get_time( c2, "certificate2", "notAfter"); - gCert->activation_time = _gnutls_get_time( c2, "certificate2", "notBefore"); + gCert->expiration_time = + _gnutls_get_time(c2, "certificate2", "notAfter"); + gCert->activation_time = + _gnutls_get_time(c2, "certificate2", "notBefore"); + + gCert->version = _gnutls_get_version(c2, "certificate2"); - gCert->version = _gnutls_get_version( c2, "certificate2"); - asn1_delete_structure(c2); - if (gnutls_set_datum( &gCert->raw, derCert.data, derCert.size) < 0) { + if (gnutls_set_datum(&gCert->raw, derCert.data, derCert.size) < 0) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } - gCert->valid = 0; /* if we got until here - * the certificate is valid. - */ + gCert->valid = 0; /* if we got until here + * the certificate is valid. + */ return 0; @@ -801,27 +898,33 @@ return GNUTLS_E_UNIMPLEMENTED_FEATURE; /* Returns 0 if it's ok to use the KXAlgorithm with this cert * (using KeyUsage field). 1 otherwise. */ -static int _gnutls_check_x509_key_usage( gnutls_cert* cert, KXAlgorithm alg) { +static int _gnutls_check_x509_key_usage(gnutls_cert * cert, + KXAlgorithm alg) +{ if (_gnutls_map_kx_get_cred(alg) == GNUTLS_X509PKI) { - switch(alg) { - case GNUTLS_KX_RSA: - if (cert->keyUsage!=0) { - if ( !(cert->keyUsage & X509KEY_KEY_ENCIPHERMENT)) - return 1; - else - return 0; - } - return 0; - case GNUTLS_KX_DHE_RSA: - if (cert->keyUsage!=0) { - if ( !(cert->keyUsage & X509KEY_DIGITAL_SIGNATURE)) - return 1; - else - return 0; - } - return 0; - default: - return 1; + switch (alg) { + case GNUTLS_KX_RSA: + if (cert->keyUsage != 0) { + if (! + (cert-> + keyUsage & X509KEY_KEY_ENCIPHERMENT)) + return 1; + else + return 0; + } + return 0; + case GNUTLS_KX_DHE_RSA: + if (cert->keyUsage != 0) { + if (! + (cert-> + keyUsage & X509KEY_DIGITAL_SIGNATURE)) + return 1; + else + return 0; + } + return 0; + default: + return 1; } } return 0; @@ -845,7 +948,7 @@ int _gnutls_cert_supported_kx(gnutls_cert * cert, KXAlgorithm ** alg, for (kx = 0; kx < 255; kx++) { pk = _gnutls_map_pk_get_pk(kx); if (pk == cert->subject_pk_algorithm) { - if ( _gnutls_check_x509_key_usage( cert, kx) == 0) { + if (_gnutls_check_x509_key_usage(cert, kx) == 0) { kxlist[i] = kx; i++; } @@ -858,13 +961,13 @@ int _gnutls_cert_supported_kx(gnutls_cert * cert, KXAlgorithm ** alg, *alg_size = i; - memcpy(*alg, kxlist, i*sizeof(KXAlgorithm)); + memcpy(*alg, kxlist, i * sizeof(KXAlgorithm)); return 0; } /* finds a certificate in the cert lists that contains - * common_name (or subjectAltName) field similar to name + * common_name (or subjectAltDNSName) field similar to name */ gnutls_cert *_gnutls_find_cert(gnutls_cert ** cert_list, int cert_list_length, char *name) @@ -873,8 +976,13 @@ gnutls_cert *_gnutls_find_cert(gnutls_cert ** cert_list, int i; for (i = 0; i < cert_list_length; i++) { - if (cert_list[i][0].cert_info.common_name[0] != 0 || cert_list[i][0].subjectAltName[0]!=0) { - if (strcasecmp(cert_list[i][0].cert_info.common_name, name) == 0 || strcasecmp(cert_list[i][0].subjectAltName, name) == 0) { + if (cert_list[i][0].cert_info.common_name[0] != 0 + || cert_list[i][0].subjectAltDNSName[0] != 0) { + if (strcasecmp + (cert_list[i][0].cert_info.common_name, + name) == 0 + || strcasecmp(cert_list[i][0].subjectAltDNSName, + name) == 0) { cert = &cert_list[i][0]; break; } @@ -884,17 +992,22 @@ gnutls_cert *_gnutls_find_cert(gnutls_cert ** cert_list, } /* finds the index of a certificate in the cert lists that contains - * common_name (or subjectAltName) field similar to name + * common_name (or subjectAltDNSName) field similar to name */ int _gnutls_find_cert_list_index(gnutls_cert ** cert_list, - int cert_list_length, char *name) + int cert_list_length, char *name) { int index = 0; int i; for (i = 0; i < cert_list_length; i++) { - if (cert_list[i][0].cert_info.common_name[0] != 0 || cert_list[i][0].subjectAltName[0]!=0) { - if (strcasecmp(cert_list[i][0].cert_info.common_name, name) == 0 || strcasecmp(cert_list[i][0].subjectAltName, name) == 0) { + if (cert_list[i][0].cert_info.common_name[0] != 0 + || cert_list[i][0].subjectAltDNSName[0] != 0) { + if (strcasecmp + (cert_list[i][0].cert_info.common_name, + name) == 0 + || strcasecmp(cert_list[i][0].subjectAltDNSName, + name) == 0) { index = i; break; } @@ -915,23 +1028,30 @@ int _gnutls_find_cert_list_index(gnutls_cert ** cert_list, * call this function then the client will not be asked to * send a certificate. **/ -int gnutls_x509pki_set_cert_request( GNUTLS_STATE state, CertificateRequest req) { +int gnutls_x509pki_set_cert_request(GNUTLS_STATE state, + CertificateRequest req) +{ state->gnutls_internals.send_cert_req = req; return 0; } /** - * gnutls_x509pki_set_cert_callback - Used to set a callback while selecting the proper (client) certificate + * gnutls_set_x509_cert_callback - Used to set a callback while selecting the proper (client) certificate * @cred: is an &X509PKI_CLIENT_CREDENTIALS structure. * @x509_cert_callback: is the callback function * * The callback's function form is: - * int (*callback)(gnutls_DN *client_cert, gnutls_DN *issuer_cert, int ncerts); - * where client_cert contains ncerts gnutls_DN structures which hold - * DN data from the client certificate, and issuer_cert holds DN data - * for the issuer of the certificate. Ie issuer_cert[i] is the issuer of + * int (*callback)(gnutls_DN *client_cert, gnutls_DN *issuer_cert, int ncerts, gnutls_DN* req_ca_cert, int nreqs); + * + * 'client_cert' contains 'ncerts' gnutls_DN structures which hold + * DN data from the client certificate. 'issuer_cert' holds DN data + * for the issuer of the certificate. Ie. issuer_cert[i] is the issuer of * client_cert[i]. (i < ncerts) * + * 'req_ca_cert' contains a list with the CA certificates that the server + * considers trusted. Normaly we should send a certificate that is signed + * by one of these CAs. + * * This function specifies what we (in case of a client) are going * to do when we have to send a certificate. If this callback * function is not provided then gnutls will automaticaly try to @@ -940,19 +1060,28 @@ int gnutls_x509pki_set_cert_request( GNUTLS_STATE state, CertificateRequest req) * If the callback function is provided then gnutls will call it * once with NULL parameters. If the callback function returns * a positive or zero number then gnutls will attempt to automaticaly - * choose the appropriate certificate. If this fails then it will - * call the callback function. + * choose the appropriate certificate. If gnutls fails to find an appropriate + * certificate, then it will call the callback function again with the + * appropriate parameters. * * In case the callback returned a negative number then gnutls will - * not attempt to choose the appropriate certificate and will rely + * not attempt to choose the appropriate certificate and will call again + * the callback function with the appropriate parameters, and rely * only to the return value of the callback function. * * The callback function should return the index of the certificate - * choosen by the user. + * choosen by the user (or -1 to indicate that the user + * does not want to use client authentication). * * This function returns 0 on success. **/ -int gnutls_x509pki_set_cert_callback( X509PKI_CREDENTIALS cred, int (*x509_cert_callback)(gnutls_DN*, gnutls_DN*, int)) { +int gnutls_set_x509_cert_callback(X509PKI_CREDENTIALS cred, + int (*x509_cert_callback) (gnutls_DN *, + gnutls_DN *, + int, + gnutls_DN *, + int)) +{ cred->client_cert_callback = x509_cert_callback; return 0; } diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h index 7cbb54fd93..7c6939d48f 100644 --- a/lib/gnutls_cert.h +++ b/lib/gnutls_cert.h @@ -2,7 +2,7 @@ # define GNUTLS_CERT_H #include <gnutls_pk.h> - +#include <x509_asn1.h> #include <gnutls_ui.h> typedef struct gnutls_cert { @@ -13,8 +13,8 @@ typedef struct gnutls_cert { gnutls_DN cert_info; gnutls_DN issuer_info; - opaque subjectAltName[X509_CN_SIZE]; - int subjectAltName_size; + opaque subjectAltDNSName[X509_CN_SIZE]; + int subjectAltDNSName_size; opaque signature[1024]; int signature_size; @@ -56,6 +56,7 @@ int _gnutls_find_cert_list_index(gnutls_cert ** cert_list, #define MAX_INT_DIGITS 4 void _gnutls_int2str(int k, char* data); +int _gnutls_get_name_type( node_asn *rasn, char *root, gnutls_DN * dn); #endif diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 4fce48b09b..64c4427496 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -140,8 +140,8 @@ void gnutls_perror(int error) * gnutls_strerror - Returns a string with a description of an error * @error: is an error returned by a gnutls function. Error is always a negative value. * - * This function is like strerror(). However it accepts an error returned by a gnutls - * function. + * This function is similar to strerror(). The only difference is that it + * accepts an error (number) returned by a gnutls function. **/ const char* gnutls_strerror(int error) { diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index e9558b504e..596a4aaf18 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -90,7 +90,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1 GNUTLS_INSUFFICIENT_SECURITY, GNUTLS_INTERNAL_ERROR=80, GNUTLS_USER_CANCELED=90, GNUTLS_NO_RENEGOTIATION=100 } AlertDescription; -typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus; +typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID, GNUTLS_CERT_NONE } CertificateStatus; typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest; typedef enum CloseRequest { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } CloseRequest; @@ -373,7 +373,7 @@ typedef struct { /* this is a callback function to call if no appropriate * client certificates were found. */ - int (*x509_client_cert_callback)(void*,void*,int); + int (*x509_client_cert_callback)(void*,void*,int, void*, int); } GNUTLS_INTERNALS; struct GNUTLS_STATE_INT { diff --git a/lib/gnutls_ui.c b/lib/gnutls_ui.c index 2735db27e7..13fed1f822 100644 --- a/lib/gnutls_ui.c +++ b/lib/gnutls_ui.c @@ -179,15 +179,17 @@ unsigned char gnutls_x509pki_get_certificate_request_status( X509PKI_CLIENT_AUT /** - * gnutls_x509pki_get_subject_alt_name - This function returns the peer's alternative name + * gnutls_x509pki_get_subject_dns_name - This function returns the peer's dns name, if any * @info: is an X509PKI_CLIENT_AUTH_INFO structure * - * This function will return the peer's alternative namee. This is specified in X509v3 Certificate - * Extensions. GNUTLS will only return the dnsName of the Alternative name, or a null string. + * This function will return the peer's alternative name (the dns part of it). + * This is specified in X509v3 Certificate Extensions. + * GNUTLS will only return the dnsName of the Alternative name, or a null + * string. * **/ -const char* gnutls_x509pki_get_subject_alt_name( X509PKI_CLIENT_AUTH_INFO info) { +const char* gnutls_x509pki_get_subject_dns_name( X509PKI_CLIENT_AUTH_INFO info) { if (info==NULL) return NULL; - return info->subjectAltName; + return info->subjectAltDNSName; } diff --git a/lib/gnutls_ui.h b/lib/gnutls_ui.h index 243ed65db5..6b22bd14de 100644 --- a/lib/gnutls_ui.h +++ b/lib/gnutls_ui.h @@ -10,6 +10,7 @@ #define X509_OU_SIZE 256 #define X509_L_SIZE 256 #define X509_S_SIZE 256 +#define X509_EMAIL_SIZE 256 typedef struct { char common_name[X509_CN_SIZE]; @@ -18,6 +19,7 @@ typedef struct { char organizational_unit_name[X509_OU_SIZE]; char locality_name[X509_L_SIZE]; char state_or_province_name[X509_S_SIZE]; + char email[X509_EMAIL_SIZE]; } gnutls_DN; /* For key Usage, test as: @@ -50,7 +52,7 @@ int gnutls_anon_client_get_dh_bits( ANON_CLIENT_AUTH_INFO info); /* X509PKI */ -int gnutls_x509pki_set_cert_callback( X509PKI_CREDENTIALS, int (*x509_cert_callback)(gnutls_DN*, gnutls_DN*, int)); +int gnutls_set_x509_cert_callback( X509PKI_CREDENTIALS, int (*x509_cert_callback)(gnutls_DN*, gnutls_DN*, int, gnutls_DN*, int)); int gnutls_x509pki_set_cert_request( GNUTLS_STATE, CertificateRequest); const gnutls_DN* gnutls_x509pki_get_peer_dn( X509PKI_CLIENT_AUTH_INFO info); @@ -60,7 +62,7 @@ int gnutls_x509pki_get_peer_certificate_version( X509PKI_CLIENT_AUTH_INFO info) time_t gnutls_x509pki_get_peer_certificate_activation_time( X509PKI_CLIENT_AUTH_INFO info); time_t gnutls_x509pki_get_peer_certificate_expiration_time( X509PKI_CLIENT_AUTH_INFO info); unsigned char gnutls_x509pki_get_key_usage( X509PKI_CLIENT_AUTH_INFO info); -const char* gnutls_x509pki_get_subject_alt_name( X509PKI_CLIENT_AUTH_INFO info); +const char* gnutls_x509pki_get_subject_dns_name( X509PKI_CLIENT_AUTH_INFO info); #define gnutls_x509pki_server_get_peer_dn gnutls_x509pki_get_peer_dn #define gnutls_x509pki_server_get_issuer_dn gnutls_x509pki_get_issuer_dn @@ -69,7 +71,7 @@ const char* gnutls_x509pki_get_subject_alt_name( X509PKI_CLIENT_AUTH_INFO info) #define gnutls_x509pki_server_get_peer_certificate_activation_time gnutls_x509pki_get_peer_certificate_activation_time #define gnutls_x509pki_server_get_peer_certificate_expiration_time gnutls_x509pki_get_peer_certificate_expiration_time #define gnutls_x509pki_server_get_key_usage gnutls_x509pki_get_key_usage -#define gnutls_x509pki_server_get_subject_alt_name gnutls_x509pki_get_subject_alt_name +#define gnutls_x509pki_server_get_subject_dns_name gnutls_x509pki_get_subject_dns_name #define gnutls_x509pki_client_get_peer_dn gnutls_x509pki_get_peer_dn #define gnutls_x509pki_client_get_issuer_dn gnutls_x509pki_get_issuer_dn @@ -78,7 +80,7 @@ const char* gnutls_x509pki_get_subject_alt_name( X509PKI_CLIENT_AUTH_INFO info) #define gnutls_x509pki_client_get_peer_certificate_activation_time gnutls_x509pki_get_peer_certificate_activation_time #define gnutls_x509pki_client_get_peer_certificate_expiration_time gnutls_x509pki_get_peer_certificate_expiration_time #define gnutls_x509pki_client_get_key_usage gnutls_x509pki_get_key_usage -#define gnutls_x509pki_client_get_subject_alt_name gnutls_x509pki_get_subject_alt_name +#define gnutls_x509pki_client_get_subject_dns_name gnutls_x509pki_get_subject_dns_name # endif /* LIBGNUTLS_VERSION */ diff --git a/lib/x509_extensions.c b/lib/x509_extensions.c index d4d09eb6a3..16a34bd32d 100644 --- a/lib/x509_extensions.c +++ b/lib/x509_extensions.c @@ -26,17 +26,17 @@ #include <gnutls_errors.h> #include <gnutls_global.h> -/* Here we only read subjectAltName, in case of +/* Here we only read subjectAltDNSName, in case of * dnsName. Otherwise we read nothing. */ -static int _extract_subjectAltName( char* subjectAltName, opaque* extnValue, int extnValueLen) { +static int _extract_subjectAltDNSName( char* subjectAltDNSName, opaque* extnValue, int extnValueLen) { node_asn* ext; char counter[MAX_INT_DIGITS]; char name[1024]; char str[1024]; int len, k, result; - subjectAltName[0] = 0; + subjectAltDNSName[0] = 0; if (asn1_create_structure ( _gnutls_get_pkix(), "PKIX1Implicit88.GeneralNames", &ext, @@ -74,8 +74,8 @@ int len, k, result; return GNUTLS_E_ASN1_PARSING_ERROR; } - strncpy( subjectAltName, str, GMIN( len, X509_CN_SIZE-1)); - subjectAltName[X509_CN_SIZE-1] = 0; + strncpy( subjectAltDNSName, str, GMIN( len, X509_CN_SIZE-1)); + subjectAltDNSName[X509_CN_SIZE-1] = 0; break; } @@ -181,8 +181,8 @@ static int _parse_extension( gnutls_cert* cert, char* extnID, char* critical, ch return _extract_basicConstraints( &cert->CA, extnValue, extnValueLen); } - if (strcmp( extnID, "2 5 29 17")==0) { /* subjectAltName */ - return _extract_subjectAltName( cert->subjectAltName, extnValue, extnValueLen); + if (strcmp( extnID, "2 5 29 17")==0) { /* subjectAltDNSName */ + return _extract_subjectAltDNSName( cert->subjectAltDNSName, extnValue, extnValueLen); } #ifdef DEBUG @@ -57,7 +57,8 @@ PRINTX( "L:", X->locality_name); \ PRINTX( "S:", X->state_or_province_name); \ PRINTX( "C:", X->country); \ - PRINTX( "SAN:", gnutls_x509pki_client_get_subject_alt_name(x509_info)) + PRINTX( "E:", X->email); \ + PRINTX( "SAN:", gnutls_x509pki_client_get_subject_dns_name(x509_info)) static int print_info( GNUTLS_STATE state) { const char *tmp; @@ -87,6 +88,9 @@ const gnutls_DN* dn; case GNUTLS_CERT_TRUSTED: printf("- Peer's X509 Certificate was verified\n"); break; + case GNUTLS_CERT_NONE: + printf("- Peer did not send any X509 Certificate.\n"); + break; case GNUTLS_CERT_INVALID: default: printf("- Peer's X509 Certificate was invalid\n"); @@ -121,6 +125,34 @@ const gnutls_DN* dn; return 0; } +int cert_callback( gnutls_DN *client_cert, gnutls_DN *issuer_cert, int ncerts, gnutls_DN* req_ca_cert, int nreqs) { + + if (client_cert==NULL) { + return 0; /* means the we will only be called again + * if the library cannot determine which + * certificate to send + */ + } + +#if 0 + /* here we should prompt the user and ask him + * which certificate to choose. Too bored to + * implement that. --nmav + */ + for (i=0;i<ncerts;i++){ + fprintf(stderr, "%s.", client_cert->common_name); + fprintf(stderr, "%s\n", issuer_cert->common_name); + } + for (i=0;i<nreqs;i++){ + fprintf(stderr, "%s.", req_ca_cert->common_name); + } + fprintf(stderr, "\n"); + return 0; +#endif + + return -1; /* send no certificate to the peer */ +} + int main(int argc, char** argv) { int err, ret; @@ -160,6 +192,7 @@ int main(int argc, char** argv) } gnutls_set_x509_client_trust( xcred, CAFILE, CRLFILE); gnutls_set_x509_client_key( xcred, CLICERTFILE, CLIKEYFILE); + gnutls_set_x509_cert_callback( xcred, cert_callback); /* SRP stuff */ if (gnutls_allocate_srp_client_sc( &cred)<0) { diff --git a/src/serv.c b/src/serv.c index 8f7eebf161..5cddf87155 100644 --- a/src/serv.c +++ b/src/serv.c @@ -109,7 +109,8 @@ GNUTLS_STATE initialize_state() PRINTX( "L:", X->locality_name); \ PRINTX( "S:", X->state_or_province_name); \ PRINTX( "C:", X->country); \ - PRINTX( "SAN:", gnutls_x509pki_client_get_subject_alt_name(x509_info)) + PRINTX( "E:", X->email); \ + PRINTX( "SAN:", gnutls_x509pki_client_get_subject_dns_name(x509_info)) void print_info(GNUTLS_STATE state) { @@ -160,6 +161,9 @@ void print_info(GNUTLS_STATE state) case GNUTLS_CERT_TRUSTED: printf("- Peer's X509 Certificate was verified\n"); break; + case GNUTLS_CERT_NONE: + printf("- Peer did not send any certificate.\n"); + break; case GNUTLS_CERT_INVALID: default: printf("- Peer's X509 Certificate was invalid\n"); |