summaryrefslogtreecommitdiff
path: root/lib/gnutls_x509.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2003-02-09 09:37:35 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2003-02-09 09:37:35 +0000
commite25325c312e339bd1a3624de4b877c73960b58c7 (patch)
tree30c5ab7919ace214d2c4f7e5773538ffdb127cf2 /lib/gnutls_x509.c
parenta72c0ee5e22684e8e995e1fc4871fa06e1edc30f (diff)
downloadgnutls-e25325c312e339bd1a3624de4b877c73960b58c7.tar.gz
Several internal changes to use the new certificate API. CRL support is complete.
Diffstat (limited to 'lib/gnutls_x509.c')
-rw-r--r--lib/gnutls_x509.c978
1 files changed, 462 insertions, 516 deletions
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index feb49b7b36..41ca970935 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -33,9 +33,7 @@
#include <gnutls_algorithms.h>
#include <gnutls_global.h>
#include <gnutls_record.h>
-#include <x509_verify.h>
#include <gnutls_sig.h>
-#include <x509_extensions.h>
#include <gnutls_state.h>
#include <gnutls_pk.h>
#include <gnutls_str.h>
@@ -44,38 +42,27 @@
#include <gnutls_privkey.h>
#include <gnutls_x509.h>
#include "x509/common.h"
+#include "x509/x509.h"
+#include "x509/verify.h"
#include "x509/compat.h"
#include "x509/mpi.h"
+#include "x509/pkcs7.h"
/*
* some x509 certificate parsing functions.
*/
-int _gnutls_x509_get_version(ASN1_TYPE c2, const char *root)
-{
- opaque gversion[5];
- char name[1024];
- int len, result;
-
- _gnutls_str_cpy(name, sizeof(name), root);
- _gnutls_str_cat(name, sizeof(name), ".tbsCertificate.version");
-
- len = sizeof(gversion) - 1;
- if ((result = asn1_read_value(c2, name, gversion, &len)) != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
- return (int) gversion[0] + 1;
-}
-
-
-#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(peer_certificate_list[x])
+#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) { \
+ if (peer_certificate_list[x]) \
+ gnutls_x509_certificate_deinit(peer_certificate_list[x]); \
+ } \
+ gnutls_free( peer_certificate_list)
/*-
* _gnutls_x509_cert_verify_peers - This function returns the peer's certificate status
* @session: is a gnutls session
*
- * This function will try to verify the peer's certificate and return it's status (TRUSTED, EXPIRED etc.).
+ * This function will try to verify the peer's certificate and return it's status (TRUSTED, REVOKED etc.).
* The return value (status) should be one of the gnutls_certificate_status enumerated elements.
* However you must also check the peer's name in order to check if the verified certificate belongs to the
* actual peer. Returns a negative error code in case of an error, or GNUTLS_E_NO_CERTIFICATE_FOUND if no certificate was sent.
@@ -85,8 +72,8 @@ int _gnutls_x509_cert_verify_peers(gnutls_session session)
{
CERTIFICATE_AUTH_INFO info;
const gnutls_certificate_credentials cred;
- int verify;
- gnutls_cert *peer_certificate_list;
+ unsigned int verify;
+ gnutls_x509_certificate *peer_certificate_list;
int peer_certificate_list_size, i, x, ret;
CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
@@ -113,160 +100,44 @@ int _gnutls_x509_cert_verify_peers(gnutls_session session)
peer_certificate_list =
gnutls_calloc(1,
peer_certificate_list_size *
- sizeof(gnutls_cert));
+ sizeof(gnutls_x509_certificate));
if (peer_certificate_list == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
for (i = 0; i < peer_certificate_list_size; i++) {
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(&peer_certificate_list[i],
- info->
- raw_certificate_list[i], 0)) <
- 0) {
+ ret = gnutls_x509_certificate_init( &peer_certificate_list[i]);
+ if (ret < 0) {
gnutls_assert();
CLEAR_CERTS;
- gnutls_free(peer_certificate_list);
- return ret;
- }
- }
-
- /* Verify certificate
- */
- verify =
- _gnutls_x509_verify_certificate(peer_certificate_list,
- peer_certificate_list_size,
- cred->x509_ca_list, cred->x509_ncas, NULL, 0);
-
- CLEAR_CERTS;
- gnutls_free(peer_certificate_list);
-
- if (verify < 0) {
- gnutls_assert();
- return verify;
- }
-
-
- return verify;
-}
-
-#define CLEAR_CERTS_CA for(x=0;x<peer_certificate_list_size;x++) _gnutls_free_cert(peer_certificate_list[x]); \
- for(x=0;x<ca_certificate_list_size;x++) _gnutls_free_cert(ca_certificate_list[x])
-/**
- * gnutls_x509_verify_certificate - This function verifies given certificate list
- * @cert_list: is the certificate list to be verified
- * @cert_list_length: holds the number of certificate in cert_list
- * @CA_list: is the CA list which will be used in verification
- * @CA_list_length: holds the number of CA certificate in CA_list
- * @CRL_list: not used
- * @CRL_list_length: not used
- *
- * This function will try to verify the given certificate list and return it's status (TRUSTED, EXPIRED etc.).
- * The return value (status) should be one or more of the gnutls_certificate_status
- * enumerated elements bitwise or'd. Note that expiration and activation dates are not checked
- * by this function, you should check them using the appropriate functions.
- *
- * This function understands the basicConstraints (2 5 29 19) PKIX extension.
- * This means that only a certificate authority can sign a certificate.
- *
- * However you must also check the peer's name in order to check if the verified certificate belongs to the
- * actual peer.
- *
- * The return value (status) should be one or more of the gnutls_certificate_status
- * enumerated elements bitwise or'd.
- *
- * GNUTLS_CERT_NOT_TRUSTED\: the peer's certificate is not trusted.
- *
- * GNUTLS_CERT_INVALID\: the certificate chain is broken.
- *
- * GNUTLS_CERT_REVOKED\: the certificate has been revoked
- * (not implemented yet).
- *
- * GNUTLS_CERT_CORRUPTED\: the certificate is corrupted.
- *
- * A negative error code is returned in case of an error.
- * GNUTLS_E_NO_CERTIFICATE_FOUND is returned to indicate that
- * no certificate was sent by the peer.
- *
- *
- **/
-int gnutls_x509_verify_certificate( const gnutls_datum* cert_list, int cert_list_length, const gnutls_datum * CA_list, int CA_list_length, const gnutls_datum* CRL_list, int CRL_list_length)
-{
- int verify;
- gnutls_cert *peer_certificate_list;
- gnutls_cert *ca_certificate_list;
- int peer_certificate_list_size, i, x, ret, ca_certificate_list_size;
-
- if (cert_list == NULL || cert_list_length == 0)
- return GNUTLS_E_NO_CERTIFICATE_FOUND;
-
- /* generate a list of gnutls_certs based on the auth info
- * raw certs.
- */
- peer_certificate_list_size = cert_list_length;
- peer_certificate_list =
- gnutls_calloc(1,
- peer_certificate_list_size *
- sizeof(gnutls_cert));
- if (peer_certificate_list == NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- ca_certificate_list_size = CA_list_length;
- ca_certificate_list =
- gnutls_calloc(1,
- ca_certificate_list_size *
- sizeof(gnutls_cert));
- if (ca_certificate_list == NULL) {
- gnutls_assert();
- gnutls_free( peer_certificate_list);
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- /* convert certA_list to gnutls_cert* list
- */
- for (i = 0; i < peer_certificate_list_size; i++) {
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(&peer_certificate_list[i],
- cert_list[i], 0)) < 0) {
- gnutls_assert();
- CLEAR_CERTS_CA;
- gnutls_free( peer_certificate_list);
- gnutls_free( ca_certificate_list);
return ret;
}
- }
-
- /* convert CA_list to gnutls_cert* list
- */
- for (i = 0; i < ca_certificate_list_size; i++) {
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(&ca_certificate_list[i],
- CA_list[i], 0)) < 0) {
+
+ ret =
+ gnutls_x509_certificate_import(peer_certificate_list[i],
+ &info->
+ raw_certificate_list[i], GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
gnutls_assert();
- CLEAR_CERTS_CA;
- gnutls_free( peer_certificate_list);
- gnutls_free( ca_certificate_list);
+ CLEAR_CERTS;
return ret;
}
}
/* Verify certificate
*/
- verify =
- _gnutls_x509_verify_certificate(peer_certificate_list,
+ ret =
+ gnutls_x509_certificate_list_verify(peer_certificate_list,
peer_certificate_list_size,
- ca_certificate_list, ca_certificate_list_size, NULL, 0);
+ cred->x509_ca_list, cred->x509_ncas,
+ cred->x509_crl_list, cred->x509_ncrls, 0, &verify);
- CLEAR_CERTS_CA;
- gnutls_free( peer_certificate_list);
- gnutls_free( ca_certificate_list);
+ CLEAR_CERTS;
- if (verify < 0) {
+ if (ret < 0) {
gnutls_assert();
- return verify;
+ return ret;
}
return verify;
@@ -279,9 +150,11 @@ int gnutls_x509_verify_certificate( const gnutls_datum* cert_list, int cert_list
/* returns error if the certificate has different algorithm than
* the given key parameters.
*/
-static int _gnutls_check_key_cert_match( gnutls_certificate_credentials res) {
+static int _gnutls_check_key_cert_match( gnutls_certificate_credentials res)
+{
+int pk = res->cert_list[res->ncerts-1][0].subject_pk_algorithm;
- if (res->pkey[res->ncerts-1].pk_algorithm != res->cert_list[res->ncerts-1][0].subject_pk_algorithm) {
+ if (res->pkey[res->ncerts-1].pk_algorithm != (unsigned int)pk) {
gnutls_assert();
return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
}
@@ -316,32 +189,54 @@ static int parse_der_cert_mem( gnutls_cert** cert_list, int* ncerts,
tmp.data = (opaque*)input_cert;
tmp.size = input_cert_size;
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(
- &cert_list[0][i - 1],
- tmp, 0)) < 0) {
+ ret = _gnutls_x509_cert2gnutls_cert(
+ &cert_list[0][i - 1], &tmp, 0);
+ if ( ret < 0) {
gnutls_assert();
return ret;
}
-
+
*ncerts = i;
return 1; /* one certificate parsed */
}
+#define CERT_PEM 1
/* Reads a PKCS7 base64 encoded certificate list from memory and stores it to
* a gnutls_cert structure.
* returns the number of certificate parsed
*/
-static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts,
- const char *input_cert, int input_cert_size)
+static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts, const
+ char *input_cert, int input_cert_size, int flags)
{
int i, j, count;
gnutls_datum tmp, tmp2;
int ret;
opaque pcert[MAX_X509_CERT_SIZE];
int pcert_size;
+ gnutls_pkcs7 pkcs7;
+
+ ret = gnutls_pkcs7_init( &pkcs7);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (flags & CERT_PEM)
+ ret = gnutls_pkcs7_import( pkcs7, &tmp, GNUTLS_X509_FMT_PEM);
+ else
+ ret = gnutls_pkcs7_import( pkcs7, &tmp, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ /* if we failed to read the structure,
+ * then just try to decode a plain DER
+ * certificate.
+ */
+ gnutls_assert();
+ gnutls_pkcs7_deinit(pkcs7);
+ return parse_der_cert_mem( cert_list, ncerts,
+ input_cert, input_cert_size);
+ }
i = *ncerts + 1;
@@ -349,22 +244,19 @@ static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts,
tmp.data = (opaque*)input_cert;
tmp.size = input_cert_size;
- count = gnutls_x509_pkcs7_extract_certificate_count( &tmp);
+ ret = gnutls_pkcs7_get_certificate_count( pkcs7);
- if (count <= 0) {
+ if (ret < 0) {
gnutls_assert();
- /* if we failed to read the count,
- * then just try to decode a plain DER
- * certificate.
- */
- return parse_der_cert_mem( cert_list, ncerts,
- input_cert, input_cert_size);
+ gnutls_pkcs7_deinit(pkcs7);
+ return ret;
}
+ count = ret;
j = count - 1;
do {
pcert_size = sizeof(pcert);
- ret = gnutls_x509_pkcs7_extract_certificate( &tmp, j, pcert, &pcert_size);
+ ret = gnutls_pkcs7_get_certificate( pkcs7, j, pcert, &pcert_size);
j--;
/* if the current certificate is too long, just ignore
@@ -387,21 +279,23 @@ static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts,
tmp2.data = pcert;
tmp2.size = pcert_size;
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(
- &cert_list[0][i - 1],
- tmp2, 0)) < 0) {
+ ret = _gnutls_x509_cert2gnutls_cert(
+ &cert_list[0][i - 1], &tmp2, 0);
+
+ if ( ret < 0) {
gnutls_assert();
+ gnutls_pkcs7_deinit(pkcs7);
return ret;
}
-
+
i++;
}
} while (ret >= 0 && j >= 0);
-
+
*ncerts = i - 1;
+ gnutls_pkcs7_deinit(pkcs7);
return count;
}
@@ -412,9 +306,9 @@ static int parse_pkcs7_cert_mem( gnutls_cert** cert_list, int* ncerts,
static int parse_pem_cert_mem( gnutls_cert** cert_list, int* ncerts,
const char *input_cert, int input_cert_size)
{
- int siz, i, siz2;
- opaque *b64;
+ int siz, siz2, i;
const char *ptr;
+ opaque *ptr2;
gnutls_datum tmp;
int ret, count;
@@ -422,18 +316,9 @@ static int parse_pem_cert_mem( gnutls_cert** cert_list, int* ncerts,
{
siz = strlen( ptr);
- siz2 = _gnutls_fbase64_decode( NULL, ptr, siz, &b64);
-
- if (siz2 < 0) {
- gnutls_assert();
- return GNUTLS_E_BASE64_DECODING_ERROR;
- }
-
- ret = parse_pkcs7_cert_mem( cert_list, ncerts, b64,
- siz2);
+ ret = parse_pkcs7_cert_mem( cert_list, ncerts, ptr,
+ siz, CERT_PEM);
- gnutls_free(b64);
-
return ret;
}
@@ -452,7 +337,8 @@ static int parse_pem_cert_mem( gnutls_cert** cert_list, int* ncerts,
count = 0;
do {
- siz2 = _gnutls_fbase64_decode(NULL, ptr, siz, &b64);
+
+ siz2 = _gnutls_fbase64_decode(NULL, ptr, siz, &ptr2);
siz -= siz2;
if (siz2 < 0) {
@@ -467,23 +353,19 @@ static int parse_pem_cert_mem( gnutls_cert** cert_list, int* ncerts,
if ( *cert_list == NULL) {
gnutls_assert();
- gnutls_free(b64);
return GNUTLS_E_MEMORY_ERROR;
}
- tmp.data = b64;
+ tmp.data = ptr2;
tmp.size = siz2;
- if ((ret =
- _gnutls_x509_cert2gnutls_cert(
- &cert_list[0][i - 1],
- tmp, 0)) < 0) {
- gnutls_free(b64);
+ ret = _gnutls_x509_cert2gnutls_cert(
+ &cert_list[0][i - 1], &tmp, 0);
+ if ( ret < 0) {
gnutls_assert();
return ret;
}
- gnutls_free(b64);
-
+
/* now we move ptr after the pem header
*/
ptr++;
@@ -506,14 +388,16 @@ static int parse_pem_cert_mem( gnutls_cert** cert_list, int* ncerts,
/* Reads a DER or PEM certificate from memory
*/
-static int read_cert_mem(gnutls_certificate_credentials res, const char *cert, int cert_size,
+static
+int read_cert_mem(gnutls_certificate_credentials res, const char *cert, int cert_size,
gnutls_x509_certificate_format type)
{
int ret;
/* allocate space for the certificate to add
*/
- res->cert_list = gnutls_realloc_fast( res->cert_list, (1+ res->ncerts)*sizeof(gnutls_cert*));
+ res->cert_list = gnutls_realloc_fast( res->cert_list,
+ (1+ res->ncerts)*sizeof(gnutls_cert*));
if ( res->cert_list==NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
@@ -530,8 +414,8 @@ static int read_cert_mem(gnutls_certificate_credentials res, const char *cert, i
res->cert_list_length[res->ncerts] = 0;
if (type==GNUTLS_X509_FMT_DER)
- ret = parse_pkcs7_cert_mem( &res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts],
- cert, cert_size);
+ ret = parse_pkcs7_cert_mem( &res->cert_list[res->ncerts],
+ &res->cert_list_length[res->ncerts], cert, cert_size, 0);
else
ret = parse_pem_cert_mem( &res->cert_list[res->ncerts], &res->cert_list_length[res->ncerts],
cert, cert_size);
@@ -544,21 +428,6 @@ static int read_cert_mem(gnutls_certificate_credentials res, const char *cert, i
return ret;
}
-/* Reads a base64 encoded CA list from memory
- * This is to be called once.
- */
-static int read_ca_mem(gnutls_certificate_credentials res, const char *ca, int ca_size,
- gnutls_x509_certificate_format type)
-{
-
- if (type==GNUTLS_X509_FMT_DER)
- return parse_der_cert_mem( &res->x509_ca_list, &res->x509_ncas,
- ca, ca_size);
- else
- return parse_pem_cert_mem( &res->x509_ca_list, &res->x509_ncas,
- ca, ca_size);
-
-}
/* This will check if the given DER key is a PKCS-1 RSA key.
@@ -762,29 +631,6 @@ static int read_cert_file(gnutls_certificate_credentials res, const char *certfi
}
-/* Reads a base64 encoded CA file (file contains multiple certificate
- * authorities). This is to be called once.
- */
-static int read_ca_file(gnutls_certificate_credentials res, const char *cafile,
- gnutls_x509_certificate_format type)
-{
- int siz;
- char x[MAX_FILE_SIZE];
- FILE *fd1;
-
- fd1 = fopen(cafile, "rb");
- if (fd1 == NULL) {
- gnutls_assert();
- return GNUTLS_E_FILE_ERROR;
- }
-
- siz = fread(x, 1, sizeof(x)-1, fd1);
- fclose(fd1);
-
- x[siz] = 0;
-
- return read_ca_mem( res, x, siz, type);
-}
/* Reads PKCS-1 RSA private key file or a DSA file (in the format openssl
@@ -897,7 +743,8 @@ int gnutls_certificate_set_x509_key_file(gnutls_certificate_credentials res, con
}
static int generate_rdn_seq( gnutls_certificate_credentials res) {
-gnutls_datum tmp;
+gnutls_const_datum tmp;
+gnutls_datum _tmp;
int ret;
uint size, i;
opaque *pdata;
@@ -915,7 +762,8 @@ opaque *pdata;
size = 0;
for (i = 0; i < res->x509_ncas; i++) {
- if ((ret = _gnutls_find_dn(&tmp, &res->x509_ca_list[i])) < 0) {
+ if ((ret = _gnutls_x509_certificate_get_raw_issuer_dn(
+ res->x509_ca_list[i], &tmp)) < 0) {
gnutls_assert();
return ret;
}
@@ -935,20 +783,194 @@ opaque *pdata;
pdata = res->x509_rdn_sequence.data;
for (i = 0; i < res->x509_ncas; i++) {
- if ((ret = _gnutls_find_dn(&tmp, &res->x509_ca_list[i])) < 0) {
+ if ((ret = _gnutls_x509_certificate_get_raw_issuer_dn(
+ res->x509_ca_list[i], &tmp)) < 0) {
gnutls_free(res->x509_rdn_sequence.data);
res->x509_rdn_sequence.size = 0;
res->x509_rdn_sequence.data = NULL;
gnutls_assert();
return ret;
}
- _gnutls_write_datum16(pdata, tmp);
+
+ _tmp.data = (char*) tmp.data;
+ _tmp.size = tmp.size;
+ _gnutls_write_datum16(pdata, _tmp);
pdata += (2 + tmp.size);
}
return 0;
}
+
+
+
+/* Returns 0 if it's ok to use the gnutls_kx_algorithm with this
+ * certificate (uses the KeyUsage field).
+ */
+int _gnutls_check_key_usage( const gnutls_cert* cert,
+ gnutls_kx_algorithm alg)
+{
+ unsigned int keyUsage = 0;
+ int encipher_type;
+
+ if ( cert==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ /* FIXME: check here */
+ if (_gnutls_map_kx_get_cred(alg, 1) == GNUTLS_CRD_CERTIFICATE ||
+ _gnutls_map_kx_get_cred(alg, 0) == GNUTLS_CRD_CERTIFICATE)
+ {
+
+ keyUsage = cert->keyUsage;
+
+ encipher_type = _gnutls_kx_encipher_type( alg);
+
+ if (keyUsage != 0 && encipher_type != CIPHER_IGN) {
+ /* If keyUsage has been set in the certificate
+ */
+
+ if ( encipher_type == CIPHER_ENCRYPT) {
+ /* If the key exchange method requires an encipher
+ * type algorithm, and key's usage does not permit
+ * encipherment, then fail.
+ */
+ if (!(keyUsage & KEY_KEY_ENCIPHERMENT))
+ return
+ GNUTLS_E_KEY_USAGE_VIOLATION;
+ }
+
+ if ( encipher_type == CIPHER_SIGN) {
+ /* The same as above, but for sign only keys
+ */
+ if (!(keyUsage & KEY_DIGITAL_SIGNATURE))
+ return
+ GNUTLS_E_KEY_USAGE_VIOLATION;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+static int parse_pem_ca_mem( gnutls_x509_certificate** cert_list, int* ncerts,
+ const char *input_cert, int input_cert_size)
+{
+ int siz, i;
+ const char *ptr;
+ gnutls_datum tmp;
+ int ret, count;
+
+ /* move to the certificate
+ */
+ ptr = strstr( input_cert, PEM_CERT_SEP);
+ if (ptr == NULL) ptr = strstr( input_cert, PEM_CERT_SEP2);
+
+ if (ptr == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_BASE64_DECODING_ERROR;
+ }
+ siz = strlen( ptr);
+
+ i = *ncerts + 1;
+ count = 0;
+
+ do {
+
+ *cert_list =
+ (gnutls_x509_certificate *) gnutls_realloc_fast( *cert_list,
+ i *
+ sizeof(gnutls_x509_certificate));
+
+ if ( *cert_list == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ ret = gnutls_x509_certificate_init( &cert_list[0][i - 1]);
+ if ( ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ tmp.data = (char*)ptr;
+ tmp.size = siz;
+
+ ret =
+ gnutls_x509_certificate_import(
+ cert_list[0][i - 1],
+ &tmp, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* now we move ptr after the pem header
+ */
+ ptr++;
+ /* find the next certificate (if any)
+ */
+ ptr = strstr(ptr, PEM_CERT_SEP);
+ if (ptr == NULL) ptr = strstr( input_cert, PEM_CERT_SEP2);
+
+ i++;
+ count++;
+
+ } while ( ptr != NULL);
+
+ *ncerts = i - 1;
+
+ return count;
+}
+
+/* Reads a DER encoded certificate list from memory and stores it to
+ * a gnutls_cert structure. This is only called if PKCS7 read fails.
+ * returns the number of certificates parsed (1)
+ */
+static int parse_der_ca_mem( gnutls_x509_certificate** cert_list, int* ncerts,
+ const char *input_cert, int input_cert_size)
+{
+ int i;
+ gnutls_datum tmp;
+ int ret;
+
+ i = *ncerts + 1;
+
+ *cert_list =
+ (gnutls_x509_certificate *) gnutls_realloc_fast( *cert_list,
+ i *
+ sizeof(gnutls_x509_certificate));
+
+ if ( *cert_list == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ tmp.data = (opaque*)input_cert;
+ tmp.size = input_cert_size;
+
+ ret = gnutls_x509_certificate_init( &cert_list[0][i - 1]);
+ if ( ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret =
+ gnutls_x509_certificate_import(
+ cert_list[0][i - 1],
+ &tmp, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ *ncerts = i;
+
+ return 1; /* one certificate parsed */
+}
+
/**
* gnutls_certificate_set_x509_trust_mem - Used to add trusted CAs in a gnutls_certificate_credentials structure
* @res: is an &gnutls_certificate_credentials structure.
@@ -964,8 +986,12 @@ int gnutls_certificate_set_x509_trust_mem(gnutls_certificate_credentials res,
{
int ret, ret2;
- if ((ret = read_ca_mem(res, CA->data, CA->size, type)) < 0)
- return ret;
+ if (type==GNUTLS_X509_FMT_DER)
+ return parse_der_ca_mem( &res->x509_ca_list, &res->x509_ncas,
+ CA->data, CA->size);
+ else
+ return parse_pem_ca_mem( &res->x509_ca_list, &res->x509_ncas,
+ CA->data, CA->size);
if ((ret2 = generate_rdn_seq(res)) < 0)
return ret2;
@@ -989,9 +1015,34 @@ int gnutls_certificate_set_x509_trust_file(gnutls_certificate_credentials res,
const char *CAFILE, gnutls_x509_certificate_format type)
{
int ret, ret2;
+ int siz;
+ char x[MAX_FILE_SIZE];
+ FILE *fd1;
+
+ /* FIXME: does not work on long files
+ */
+ fd1 = fopen(CAFILE, "rb");
+ if (fd1 == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ siz = fread(x, 1, sizeof(x)-1, fd1);
+ fclose(fd1);
+
+ x[siz] = 0;
- if ((ret = read_ca_file(res, CAFILE, type)) < 0)
+ if (type==GNUTLS_X509_FMT_DER)
+ ret = parse_der_ca_mem( &res->x509_ca_list, &res->x509_ncas,
+ x, siz);
+ else
+ ret = parse_pem_ca_mem( &res->x509_ca_list, &res->x509_ncas,
+ x, siz);
+
+ if (ret < 0) {
+ gnutls_assert();
return ret;
+ }
if ((ret2 = generate_rdn_seq(res)) < 0)
return ret2;
@@ -999,322 +1050,217 @@ int gnutls_certificate_set_x509_trust_file(gnutls_certificate_credentials res,
return ret;
}
+static int parse_pem_crl_mem( gnutls_x509_crl** crl_list, int* ncrls,
+ const char *input_crl, int input_crl_size)
+{
+ int siz, i;
+ const char *ptr;
+ gnutls_datum tmp;
+ int ret, count;
-/* Extracts DSA and RSA parameters from a certificate.
- */
-static
-int _gnutls_extract_x509_cert_mpi_params( const char* ALGO_OID, gnutls_cert * gCert,
- ASN1_TYPE c2, const char* name, char* tmpstr, int tmpstr_size) {
-int len, result;
-char name1[128];
-
- _gnutls_str_cpy( name1, sizeof(name1), name);
- _gnutls_str_cat( name1, sizeof(name1), ".tbsCertificate.subjectPublicKeyInfo.subjectPublicKey");
-
- len = tmpstr_size - 1;
- result =
- asn1_read_value
- (c2, name1, tmpstr, &len);
-
- if (result != ASN1_SUCCESS) {
+ /* move to the certificate
+ */
+ ptr = strstr( input_crl, PEM_CRL_SEP);
+ if (ptr == NULL) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ return GNUTLS_E_BASE64_DECODING_ERROR;
}
- gCert->subject_pk_algorithm = _gnutls_x509_oid2pk_algorithm( ALGO_OID);
-
- switch( gCert->subject_pk_algorithm) {
- case GNUTLS_PK_RSA:
- /* params[0] is the modulus,
- * params[1] is the exponent
- */
- if ((sizeof(gCert->params) / sizeof(GNUTLS_MPI)) < RSA_PUBLIC_PARAMS) {
- gnutls_assert();
- /* internal error. Increase the GNUTLS_MPIs in params */
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- if ((result =
- _gnutls_x509_read_rsa_params(tmpstr, len / 8, gCert->params)) < 0) {
- gnutls_assert();
- return result;
- }
- gCert->params_size = RSA_PUBLIC_PARAMS;
-
- return 0;
- break;
- case GNUTLS_PK_DSA:
- /* params[0] is p,
- * params[1] is q,
- * params[2] is q,
- * params[3] is pub.
- */
-
- if ((sizeof(gCert->params) / sizeof(GNUTLS_MPI)) < DSA_PUBLIC_PARAMS) {
- gnutls_assert();
- /* internal error. Increase the GNUTLS_MPIs in params */
- return GNUTLS_E_INTERNAL_ERROR;
- }
+ siz = strlen( ptr);
- if ((result =
- _gnutls_x509_read_dsa_pubkey(tmpstr, len / 8, gCert->params)) < 0) {
- gnutls_assert();
- return result;
- }
+ i = *ncrls + 1;
+ count = 0;
- /* Now read the parameters
- */
- _gnutls_str_cpy( name1, sizeof(name1), name);
- _gnutls_str_cat( name1, sizeof(name1), ".tbsCertificate.subjectPublicKeyInfo.algorithm.parameters");
+ do {
- len = tmpstr_size - 1;
- result =
- asn1_read_value(c2, name1, tmpstr, &len);
+ *crl_list =
+ (gnutls_x509_crl *) gnutls_realloc_fast( *crl_list,
+ i *
+ sizeof(gnutls_x509_crl));
- if (result != ASN1_SUCCESS) {
+ if ( *crl_list == NULL) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ return GNUTLS_E_MEMORY_ERROR;
}
- if ((result =
- _gnutls_x509_read_dsa_params(tmpstr, len, gCert->params)) < 0) {
+ ret = gnutls_x509_crl_init( &crl_list[0][i - 1]);
+ if ( ret < 0) {
gnutls_assert();
- return result;
+ return ret;
}
- gCert->params_size = DSA_PUBLIC_PARAMS;
- return 0;
- break;
+ tmp.data = (char*)ptr;
+ tmp.size = siz;
+
+ ret =
+ gnutls_x509_crl_import(
+ crl_list[0][i - 1],
+ &tmp, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
- default:
- /* other types like DH
- * currently not supported
+ /* now we move ptr after the pem header
*/
- gnutls_assert();
- _gnutls_log("X509 certificate: Found algorithm: %s\n", ALGO_OID);
-
- gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN;
-
- return GNUTLS_E_X509_CERTIFICATE_ERROR;
- }
-}
+ ptr++;
+ /* find the next certificate (if any)
+ */
+ ptr = strstr(ptr, PEM_CRL_SEP);
+ i++;
+ count++;
+ } while ( ptr != NULL);
+ *ncrls = i - 1;
-#define X509_SIG_SIZE 1024
+ return count;
+}
-/* This function will convert a der certificate, to a format
- * (structure) that gnutls can understand and use. Actually the
- * important thing on this function is that it extracts the
- * certificate's (public key) parameters.
- *
- * The noext flag is used to complete the handshake even if the
- * extensions found in the certificate are unsupported and critical.
- * The critical extensions will be catched by the verification functions.
+/* Reads a DER encoded certificate list from memory and stores it to
+ * a gnutls_cert structure. This is only called if PKCS7 read fails.
+ * returns the number of certificates parsed (1)
*/
-int _gnutls_x509_cert2gnutls_cert(gnutls_cert * gCert, gnutls_datum derCert,
- ConvFlags fast /* if non zero do not parse the whole certificate */)
+static int parse_der_crl_mem( gnutls_x509_crl** crl_list, int* ncrls,
+ const char *input_crl, int input_crl_size)
{
- int result = 0;
- ASN1_TYPE c2;
- opaque str[MAX_X509_CERT_SIZE];
- char oid[128];
- int len = sizeof(str);
-
- memset(gCert, 0, sizeof(gnutls_cert));
-
- gCert->cert_type = GNUTLS_CRT_X509;
+ int i;
+ gnutls_datum tmp;
+ int ret;
- if ( !(fast & CERT_NO_COPY)) {
- if (_gnutls_set_datum(&gCert->raw, derCert.data, derCert.size) < 0) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
- } else
- /* now we have 0 or a bitwise or of things to decode */
- fast ^= CERT_NO_COPY;
+ i = *ncrls + 1;
+ *crl_list =
+ (gnutls_x509_crl *) gnutls_realloc_fast( *crl_list,
+ i *
+ sizeof(gnutls_x509_crl));
- if ((result=_gnutls_asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.Certificate", &c2,
- "cert"))
- != ASN1_SUCCESS) {
+ if ( *crl_list == NULL) {
gnutls_assert();
- _gnutls_free_datum( &gCert->raw);
- return _gnutls_asn2err(result);
- }
-
- if (fast & CERT_ONLY_EXTENSIONS) {
- result = asn1_der_decoding_element( &c2, "cert.tbsCertificate.extensions",
- derCert.data, derCert.size, NULL);
-
- if (result != ASN1_SUCCESS) {
- /* couldn't decode DER */
-
- _gnutls_log("X509 certificate: Decoding error %d\n", result);
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return _gnutls_asn2err(result);
- }
+ return GNUTLS_E_MEMORY_ERROR;
}
- if (fast & CERT_ONLY_PUBKEY) {
- result = asn1_der_decoding_element( &c2, "cert.tbsCertificate.subjectPublicKeyInfo",
- derCert.data, derCert.size, NULL);
+ tmp.data = (opaque*)input_crl;
+ tmp.size = input_crl_size;
- if (result != ASN1_SUCCESS) {
- /* couldn't decode DER */
-
- _gnutls_log("X509 certificate: Decoding error %d\n", result);
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return _gnutls_asn2err(result);
- }
+ ret = gnutls_x509_crl_init( &crl_list[0][i - 1]);
+ if ( ret < 0) {
+ gnutls_assert();
+ return ret;
}
-
- if (fast==0) {
- result = asn1_der_decoding(&c2, derCert.data, derCert.size,
- NULL);
-
- if (result != ASN1_SUCCESS) {
- /* couldn't decode DER */
- _gnutls_log("X509 certificate: Decoding error %d\n", result);
-
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return _gnutls_asn2err(result);
- }
+
+ ret =
+ gnutls_x509_crl_import(
+ crl_list[0][i - 1],
+ &tmp, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
}
-
- if (fast==0) { /* decode all */
- len = gCert->signature.size = X509_SIG_SIZE;
- gCert->signature.data = gnutls_malloc( gCert->signature.size);
- if (gCert->signature.data==NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
+ *ncrls = i;
- result =
- asn1_read_value
- (c2, "cert.signature", gCert->signature.data, &len);
+ return 1; /* one certificate parsed */
+}
- if ((len % 8) != 0) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- _gnutls_free_datum( &gCert->signature);
- return GNUTLS_E_UNIMPLEMENTED_FEATURE;
- }
-
- len /= 8; /* convert to bytes */
- gCert->signature.size = len; /* put the actual sig size */
- gCert->expiration_time =
- _gnutls_x509_get_time(c2, "cert.tbsCertificate.validity.notAfter");
- gCert->activation_time =
- _gnutls_x509_get_time(c2, "cert.tbsCertificate.validity.notBefore");
+/* Reads a DER or PEM CRL from memory
+ */
+static
+int read_crl_mem(gnutls_certificate_credentials res, const char *crl, int crl_size,
+ gnutls_x509_certificate_format type)
+{
+ int ret;
- gCert->version = _gnutls_x509_get_version(c2, "cert");
- if (gCert->version < 0) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return GNUTLS_E_ASN1_GENERIC_ERROR;
- }
+ /* allocate space for the certificate to add
+ */
+ res->x509_crl_list = gnutls_realloc_fast( res->x509_crl_list,
+ (1+ res->x509_ncrls)*sizeof(gnutls_x509_crl));
+ if ( res->x509_crl_list==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
}
- if (fast & CERT_ONLY_PUBKEY || fast == 0) {
- len = sizeof(oid) - 1;
- result =
- asn1_read_value
- (c2,
- "cert.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm",
- oid, &len);
-
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return _gnutls_asn2err(result);
- }
+ if (type==GNUTLS_X509_FMT_DER)
+ ret = parse_der_crl_mem( &res->x509_crl_list,
+ &res->x509_ncrls, crl, crl_size);
+ else
+ ret = parse_pem_crl_mem( &res->x509_crl_list,
+ &res->x509_ncrls, crl, crl_size);
- if ( (result=_gnutls_extract_x509_cert_mpi_params( oid, gCert, c2, "cert", str, sizeof(str))) < 0) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return result;
- }
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
}
- if (fast & CERT_ONLY_EXTENSIONS || fast == 0) {
- if ((result =
- _gnutls_get_ext_type(c2,
- "cert.tbsCertificate.extensions",
- gCert, fast)) < 0) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- _gnutls_free_datum( &gCert->raw);
- return result;
- }
-
- }
+ return ret;
+}
- asn1_delete_structure(&c2);
+/**
+ * gnutls_certificate_set_x509_crl_mem - Used to add CRLs in a gnutls_certificate_credentials structure
+ * @res: is an &gnutls_certificate_credentials structure.
+ * @CRL: is a list of trusted CRLs. They should have been verified before.
+ * @type: is DER or PEM
+ *
+ * This function adds the trusted CRLs in order to verify client or server
+ * certificates. This function may be called multiple times.
+ *
+ **/
+int gnutls_certificate_set_x509_crl_mem(gnutls_certificate_credentials res,
+ const gnutls_datum *CRL, gnutls_x509_certificate_format type)
+{
+ int ret;
- return 0;
+ if ((ret = read_crl_mem(res, CRL->data, CRL->size, type)) < 0)
+ return ret;
+ return ret;
}
-/* Returns 0 if it's ok to use the gnutls_kx_algorithm with this
- * certificate (uses the KeyUsage field).
- */
-int _gnutls_check_x509_key_usage( const gnutls_cert * cert,
- gnutls_kx_algorithm alg)
+/**
+ * gnutls_certificate_set_x509_crl_file - Used to add CRLs in a gnutls_certificate_credentials structure
+ * @res: is an &gnutls_certificate_credentials structure.
+ * @crlfile: is a file containing the list of verified CRLs (DER or PEM list)
+ * @type: is PEM or DER
+ *
+ * This function sets the trusted CRLs in order to verify client or server
+ * certificates. This function may be called multiple times, and the
+ * given CRLs will be appended to the crl list.
+ * Returns the number of certificate processed.
+ *
+ **/
+int gnutls_certificate_set_x509_crl_file(gnutls_certificate_credentials res,
+ const char *crlfile, gnutls_x509_certificate_format type)
{
- uint16 keyUsage;
- int encipher_type;
+ int ret;
+ int siz;
+ char x[MAX_FILE_SIZE];
+ FILE *fd1;
- if ( cert==NULL) {
+ /* FIXME: does not work on long files
+ */
+ fd1 = fopen(crlfile, "rb");
+ if (fd1 == NULL) {
gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
+ return GNUTLS_E_FILE_ERROR;
}
- /* FIXME: check here */
- if (_gnutls_map_kx_get_cred(alg, 1) == GNUTLS_CRD_CERTIFICATE ||
- _gnutls_map_kx_get_cred(alg, 0) == GNUTLS_CRD_CERTIFICATE)
- {
+ siz = fread(x, 1, sizeof(x)-1, fd1);
+ fclose(fd1);
- keyUsage = cert->keyUsage;
- encipher_type = _gnutls_kx_encipher_type( alg);
-
- if (keyUsage != 0 && encipher_type != CIPHER_IGN) {
- /* If keyUsage has been set in the certificate
- */
+ x[siz] = 0;
- if ( encipher_type == CIPHER_ENCRYPT) {
- /* If the key exchange method requires an encipher
- * type algorithm, and key's usage does not permit
- * encipherment, then fail.
- */
- if (!(keyUsage & KEY_KEY_ENCIPHERMENT))
- return
- GNUTLS_E_KEY_USAGE_VIOLATION;
- }
+ if (type==GNUTLS_X509_FMT_DER)
+ ret = parse_der_crl_mem( &res->x509_crl_list, &res->x509_ncrls,
+ x, siz);
+ else
+ ret = parse_pem_crl_mem( &res->x509_crl_list, &res->x509_ncrls,
+ x, siz);
- if ( encipher_type == CIPHER_SIGN) {
- /* The same as above, but for sign only keys
- */
- if (!(keyUsage & KEY_DIGITAL_SIGNATURE))
- return
- GNUTLS_E_KEY_USAGE_VIOLATION;
- }
- }
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
}
- return 0;
-}
-
+ return ret;
+}