summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-09-14 08:04:39 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-09-14 08:04:39 +0000
commit98dd96368dbc6a79414f359afadce10cf2481f36 (patch)
treec62dc3fe035727ca48a6dc5ba6647377c369dda0
parent192ba23c68c1a61776543ddc62c6d0d3c7b61d5a (diff)
downloadgnutls-98dd96368dbc6a79414f359afadce10cf2481f36.tar.gz
Client certificate callback has been improved
-rw-r--r--NEWS4
-rw-r--r--doc/tex/ex3.tex6
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/auth_rsa.c91
-rw-r--r--lib/auth_x509.c4
-rw-r--r--lib/auth_x509.h4
-rw-r--r--lib/gnutls.h.in2
-rw-r--r--lib/gnutls_cert.c661
-rw-r--r--lib/gnutls_cert.h7
-rw-r--r--lib/gnutls_errors.c4
-rw-r--r--lib/gnutls_int.h4
-rw-r--r--lib/gnutls_ui.c12
-rw-r--r--lib/gnutls_ui.h10
-rw-r--r--lib/x509_extensions.c14
-rw-r--r--src/cli.c35
-rw-r--r--src/serv.c6
16 files changed, 558 insertions, 308 deletions
diff --git a/NEWS b/NEWS
index f786dc5e86..90f357d7ed 100644
--- a/NEWS
+++ b/NEWS
@@ -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
diff --git a/src/cli.c b/src/cli.c
index 62fd99f2d4..c2e1d8a7df 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -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");