diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-07-20 17:50:31 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-07-20 17:50:31 +0000 |
commit | ac95734359f80e3c7771f9807e0d57b8e87093e3 (patch) | |
tree | 1ff4f329c129b9c1c5c74ed293e82926f1e2a043 /lib | |
parent | b63487a0ae5c0d4cbeeaa6d38f24a6ce6619d7dc (diff) | |
download | gnutls-ac95734359f80e3c7771f9807e0d57b8e87093e3.tar.gz |
added some kind of certificate checking
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/auth_rsa.c | 2 | ||||
-rw-r--r-- | lib/cert_verify.c | 34 | ||||
-rw-r--r-- | lib/gnutls_cert.c | 18 | ||||
-rw-r--r-- | lib/gnutls_cert.h | 8 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 1 | ||||
-rw-r--r-- | lib/gnutls_errors_int.h | 1 | ||||
-rw-r--r-- | lib/gnutls_hash_int.h | 8 | ||||
-rw-r--r-- | lib/gnutls_int.h | 4 | ||||
-rw-r--r-- | lib/gnutls_pk.c | 6 | ||||
-rw-r--r-- | lib/gnutls_pk.h | 11 | ||||
-rw-r--r-- | lib/gnutls_sig.h | 3 | ||||
-rw-r--r-- | lib/gnutls_sig_check.c | 209 |
13 files changed, 284 insertions, 27 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 1849a52e82..bea7d8fee2 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -15,7 +15,8 @@ EXTRA_DIST = debug.h gnutls_compress.h defines.h \ crypt.h libgnutls-config.in libgnutls.m4 gnutls.h.in gnutls_errors_int.h \ cert_asn1.h cert_der.h gnutls_datum.h auth_x509.h gnutls_gcry.h \ ext_dnsname.h gnutls_pk.h gnutls_record.h gnutls_cert.h \ - gnutls_privkey.h gnutls_constate.h gnutls_global.h cert_verify.h + gnutls_privkey.h gnutls_constate.h gnutls_global.h cert_verify.h \ + gnutls_sig.h lib_LTLIBRARIES = libgnutls.la libgnutls_la_SOURCES = gnutls_record.c gnutls_compress.c debug.c \ gnutls_cipher.c gnutls_buffers.c gnutls_handshake.c gnutls_num.c \ @@ -27,6 +28,7 @@ libgnutls_la_SOURCES = gnutls_record.c gnutls_compress.c debug.c \ auth_srp.c auth_srp_passwd.c gnutls_v2_compat.c auth_srp_sb64.c \ cert_ASN.y cert_asn1.c cert_der.c gnutls_datum.c auth_rsa.c \ gnutls_gcry.c ext_dnsname.c gnutls_pk.c gnutls_cert.c cert_verify.c\ - gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c + gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c \ + gnutls_sig_check.c libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c index e06467dc23..a05d87cf8e 100644 --- a/lib/auth_rsa.c +++ b/lib/auth_rsa.c @@ -311,7 +311,7 @@ int proc_rsa_client_kx(GNUTLS_KEY key, opaque * data, int data_size) } ret = _gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, key->u, - key->A); + key->A, 2); /* btype==2 */ if (ret < 0) { /* in case decryption fails then don't inform diff --git a/lib/cert_verify.c b/lib/cert_verify.c index 14d65fd3c4..4f78e502bd 100644 --- a/lib/cert_verify.c +++ b/lib/cert_verify.c @@ -25,6 +25,7 @@ #include "cert_der.h" #include "gnutls_global.h" #include "gnutls_num.h" /* GMAX */ +#include <gnutls_sig.h> /* TIME functions */ @@ -169,12 +170,14 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) opaque issuer_dn[MAX_DN]; opaque dn[MAX_DN]; +fprintf(stderr, "XXX: %s\nIII: %s\n", cert->issuer_info.common_name, issuer_cert->cert_info.common_name); /* get the issuer of 'cert' */ 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, cert->raw.data, cert->raw.size); if (result != ASN_OK) { /* couldn't decode DER */ @@ -182,9 +185,10 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) asn1_delete_structure(c2); return GNUTLS_E_ASN1_PARSING_ERROR; } + issuer_len = sizeof(issuer_dn) - 1; if ((result = - asn1_read_value(c2, "certificate2.tbsCertificate.subject.rdnSequence", issuer_dn, &issuer_len)) < 0) { + asn1_read_value(c2, "certificate2.tbsCertificate.issuer.rdnSequence", issuer_dn, &issuer_len)) < 0) { gnutls_assert(); asn1_delete_structure(c2); return GNUTLS_E_ASN1_PARSING_ERROR; @@ -198,6 +202,7 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } + result = asn1_get_der(c2, issuer_cert->raw.data, issuer_cert->raw.size); if (result != ASN_OK) { /* couldn't decode DER */ @@ -205,6 +210,7 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) asn1_delete_structure(c2); return GNUTLS_E_ASN1_PARSING_ERROR; } + len = sizeof(dn) - 1; if ((result = asn1_read_value(c2, "certificate2.tbsCertificate.subject.rdnSequence", dn, &len)) < 0) { @@ -214,10 +220,13 @@ int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert) } asn1_delete_structure(c2); +fprintf(stderr, "len: %d\nisslen: %d\n", len,issuer_len); + if (memcmp(dn, issuer_dn, GMAX(len, issuer_len)) == 0) return 0; - return -1; /* do not match */ + gnutls_assert(); + return GNUTLS_E_UNKNOWN_ERROR; /* do not match */ } @@ -233,6 +242,7 @@ static gnutls_cert *find_issuer(gnutls_cert * cert, gnutls_cert * trusted_cas, i return &trusted_cas[i]; } + gnutls_assert(); return NULL; } @@ -245,15 +255,23 @@ int gnutls_verify_certificate2(gnutls_cert * cert, gnutls_cert * trusted_cas, in gnutls_cert *issuer; CertificateStatus ret = GNUTLS_CERT_NOT_TRUSTED; - if (tcas_size > 1) + if (tcas_size >= 1) issuer = find_issuer(cert, trusted_cas, tcas_size); + else { + gnutls_assert(); + return ret; + } + /* issuer is not in trusted certificate * authorities. */ - if (issuer == NULL) + if (issuer == NULL) { + gnutls_assert(); return GNUTLS_CERT_NOT_TRUSTED; - -// ret = verify_signature(cert, issuer); + } +fprintf(stderr, "XXXissuer: %d\n", issuer->subject_pk_algorithm); + + ret = gnutls_verify_signature(cert, issuer); if (ret != GNUTLS_CERT_TRUSTED) return ret; @@ -279,9 +297,9 @@ int gnutls_verify_certificate(gnutls_cert * certificate_list, if (tcas_size == 0) { return ret; } - + for (i = 0; i < clist_size; i++) { - if (i + 1 > clist_size) + if (i + 1 >= clist_size) break; if ((ret = gnutls_verify_certificate2(&certificate_list[i], &certificate_list[i + 1], 1, NULL, 0)) != GNUTLS_CERT_TRUSTED) { diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 003e657215..b670332c10 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -82,7 +82,7 @@ int n,i; for (i=0;i<n;i++) { _gnutls_mpi_release( &cert.params[i]); } - gnutls_free( cert.params); + if (cert.params!=NULL) gnutls_free( cert.params); gnutls_free_datum( &cert.raw); @@ -691,10 +691,22 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) * currently not supported */ gnutls_assert(); - asn1_delete_structure(c2); + gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN; + gCert->params = NULL; + + } - return GNUTLS_E_UNIMPLEMENTED_FEATURE; + len = sizeof( gCert->signature); + result = + asn1_read_value + (c2, "certificate2.signature", + gCert->signature, &len); + if ((len % 8) !=0) { + gnutls_assert(); + asn1_delete_structure(c2); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; } + gCert->signature_size = len; memset( &gCert->cert_info, 0, sizeof(gCert->cert_info)); diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h index 89777e23c9..b76ff71fb2 100644 --- a/lib/gnutls_cert.h +++ b/lib/gnutls_cert.h @@ -1,6 +1,8 @@ #ifndef GNUTLS_CERT_H # define GNUTLS_CERT_H +#include <gnutls_pk.h> + typedef struct { char common_name[256]; char country[3]; @@ -10,9 +12,6 @@ typedef struct { char state_or_province_name[256]; } gnutls_DN; -typedef enum PKAlgorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, /* sign only */ - GNUTLS_PK_DH -} PKAlgorithm; typedef struct { MPI *params; /* the size of params depends on the public @@ -23,6 +22,9 @@ typedef struct { gnutls_DN cert_info; gnutls_DN issuer_info; + opaque signature[MAX_HASH_SIZE]; + int signature_size; + time_t expiration_time; time_t activation_time; diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index e804936b8e..5a147fe759 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -60,6 +60,7 @@ static gnutls_error_entry error_algorithms[] = { GNUTLS_ERROR_ENTRY( GNUTLS_E_ENCRYPTION_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_DECRYPTION_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_ENCRYPTION_FAILED, 1), + GNUTLS_ERROR_ENTRY( GNUTLS_E_PK_SIGNATURE_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_DECOMPRESSION_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_COMPRESSION_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_MEMORY_ERROR, 1), diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h index 3b04dea8fc..e89a2c7194 100644 --- a/lib/gnutls_errors_int.h +++ b/lib/gnutls_errors_int.h @@ -43,5 +43,6 @@ #define GNUTLS_E_X509_CERTIFICATE_ERROR -43 #define GNUTLS_E_PK_ENCRYPTION_FAILED -44 #define GNUTLS_E_PK_DECRYPTION_FAILED -45 +#define GNUTLS_E_PK_SIGNATURE_FAILED -46 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -250 diff --git a/lib/gnutls_hash_int.h b/lib/gnutls_hash_int.h index 3b0dbfa23c..be368331db 100644 --- a/lib/gnutls_hash_int.h +++ b/lib/gnutls_hash_int.h @@ -40,7 +40,7 @@ typedef struct { int keysize; } GNUTLS_MAC_HANDLE_INT; typedef GNUTLS_MAC_HANDLE_INT* GNUTLS_MAC_HANDLE; - +typedef GNUTLS_MAC_HANDLE GNUTLS_HASH_HANDLE; #define GNUTLS_HASH_FAILED NULL #define GNUTLS_MAC_FAILED NULL @@ -55,10 +55,10 @@ void gnutls_hmac_deinit( GNUTLS_MAC_HANDLE handle, void* digest); GNUTLS_MAC_HANDLE gnutls_mac_init_ssl3( MACAlgorithm algorithm, void* key, int keylen); void gnutls_mac_deinit_ssl3( GNUTLS_MAC_HANDLE handle, void* digest); -GNUTLS_MAC_HANDLE gnutls_hash_init(MACAlgorithm algorithm); +GNUTLS_HASH_HANDLE gnutls_hash_init(MACAlgorithm algorithm); int gnutls_hash_get_algo_len(MACAlgorithm algorithm); -int gnutls_hash(GNUTLS_MAC_HANDLE handle, const void* text, int textlen); -void gnutls_hash_deinit(GNUTLS_MAC_HANDLE handle, void* digest); +int gnutls_hash(GNUTLS_HASH_HANDLE handle, const void* text, int textlen); +void gnutls_hash_deinit(GNUTLS_HASH_HANDLE handle, void* digest); void *gnutls_ssl3_generate_random(void *secret, int secret_len, void *random, int random_len, int bytes); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 3481a29d24..663e3689cd 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -30,9 +30,9 @@ #define HARD_DEBUG #define BUFFERS_DEBUG #define RECORD_DEBUG -#define HANDSHAKE_DEBUG +#define HANDSHAKE_DEBUG*/ #define DEBUG -*/ + #define SOCKET int #define LIST ... diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index b7bbfc58a4..76b06ce6a0 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -110,7 +110,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, */ int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext, - MPI pkey, MPI n) + MPI pkey, MPI n, int btype) { int k, esize, i, ret; MPI c, res; @@ -153,13 +153,13 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext, gcry_mpi_release(res); /* EB = 00||BT||PS||00||D - * (use block type 2) + * (use block type 'btype') */ edata[0] = 0; esize++; - if (edata[0] != 0 || edata[1] != 2) { + if (edata[0] != 0 || edata[1] != btype) { gnutls_assert(); gnutls_free(edata); return GNUTLS_E_DECRYPTION_FAILED; diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index f6eb0328c7..d6e2d5d673 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -1,5 +1,14 @@ +#ifndef GNUTLS_PK_H +# define GNUTLS_PK_H + +typedef enum PKAlgorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, /* sign only */ + GNUTLS_PK_DH, GNUTLS_PK_UNKNOWN +} PKAlgorithm; + int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI ** pkey); int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, MPI pkey, MPI n); int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext, - MPI pkey, MPI n); + MPI pkey, MPI n, int btype); + +#endif /* GNUTLS_PK_H */ diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h new file mode 100644 index 0000000000..c8a759884f --- /dev/null +++ b/lib/gnutls_sig.h @@ -0,0 +1,3 @@ +int _gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum *text, MPI m, MPI e); +CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer); + diff --git a/lib/gnutls_sig_check.c b/lib/gnutls_sig_check.c new file mode 100644 index 0000000000..c96e17fa6a --- /dev/null +++ b/lib/gnutls_sig_check.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2001 Nikos Mavroyanopoulos + * + * This file is part of GNUTLS. + * + * GNUTLS is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNUTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <gnutls_int.h> +#include <gnutls_errors.h> +#include <cert_b64.h> +#include <auth_x509.h> +#include <gnutls_cert.h> +#include <cert_asn1.h> +#include <cert_der.h> +#include <gnutls_datum.h> +#include <gnutls_gcry.h> +#include <gnutls_privkey.h> +#include <gnutls_global.h> +#include <gnutls_pk.h> + +static gnutls_datum* _gnutls_get_tbs( gnutls_cert* cert) { +node_asn *c2; +gnutls_datum * ret; +opaque str[10*1024]; +int result, len; + + if (asn1_create_structure( _gnutls_get_pkix(), "Certificate", &c2, "certificate")!=ASN_OK) { + gnutls_assert(); + return NULL; + } + + result = asn1_get_der( c2, cert->raw.data, cert->raw.size); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(c2); + return NULL; + } + + len = sizeof(str)-1; + result = + asn1_read_value( c2, "certificate.tbsCertificate", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(c2); + return NULL; + } + + asn1_delete_structure(c2); + + ret = gnutls_malloc(sizeof(gnutls_cert)); + if (ret==NULL) { + gnutls_assert(); + return NULL; + } + + ret->data = gnutls_malloc( len); + if (ret->data==NULL) { + gnutls_assert(); + gnutls_free(ret); + return NULL; + } + + memcpy( ret->data, str, len); + ret->size = len; + + return ret; +} + + +/* we use DER here -- FIXME: use BER + */ +static int _gnutls_get_ber_digest_info( const gnutls_datum *info, MACAlgorithm *hash, opaque* digest, int digest_size) { +node_asn* dinfo; +int result; +opaque str[1024]; +int len; + + if (asn1_create_structure( _gnutls_get_pkcs(), "PKCS-1.DigestInfo", &dinfo, "digest_info")!=ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_get_der( dinfo, info->data, info->size); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(dinfo); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + len = sizeof(str)-1; + result = + asn1_read_value( dinfo, "digest_info.digestAlgorithm.algorithm", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(dinfo); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + *hash = -1; + + if ( strcmp(str, "1 2 840 113549 2 5")==0) { /* MD5 */ + *hash = GNUTLS_MAC_MD5; + } else + if ( strcmp(str, "xxxxxx")==0) { /* SHA1 ID */ + *hash = GNUTLS_MAC_SHA; + } + + if (*hash==-1) { +fprintf(stderr, "OID: %s\n", str); + gnutls_assert(); + return GNUTLS_E_UNIMPLEMENTED_FEATURE; + } + + len = digest_size; + result = + asn1_read_value( dinfo, "digest_info.digest", digest, &len); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(dinfo); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + asn1_delete_structure(dinfo); + + return 0; +} + +/* if hash==MD5 then we do RSA-MD5 + * if hash==SHA then we do RSA-SHA + * m is modulus + * e is public key + */ +int +_gnutls_pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI m, MPI e) +{ + MACAlgorithm hash; + int ret; + opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE]; + int digest_size; + GNUTLS_HASH_HANDLE hd; + gnutls_datum decrypted; + + + if ( (ret=_gnutls_pkcs1_rsa_decrypt( &decrypted, *signature, e, m, 1)) < 0) { + gnutls_assert(); + return ret; + } + + /* decrypted is a BER encoded data of type DigestInfo + */ + + if ( (ret = _gnutls_get_ber_digest_info( &decrypted, &hash, digest, sizeof(digest))) != 0) { + gnutls_assert(); + return ret; + } + + gnutls_free_datum( &decrypted); + + digest_size = gnutls_hash_get_algo_len(hash); + + hd = gnutls_hash_init(hash); + gnutls_hash(hd, text->data, text->size); + gnutls_hash_deinit(hd, md); + + if (memcmp( md, digest, digest_size)!=0) + return GNUTLS_E_PK_SIGNATURE_FAILED; + + return 0; +} + +CertificateStatus gnutls_verify_signature(gnutls_cert* cert, gnutls_cert* issuer) { +gnutls_datum signature; +gnutls_datum* tbs; + + if ( issuer->subject_pk_algorithm == GNUTLS_PK_RSA) { + signature.data = cert->signature; + signature.size = cert->signature_size; + + tbs = _gnutls_get_tbs( cert); + if (tbs==NULL) { + gnutls_assert(); + return GNUTLS_CERT_INVALID; + } + + if (_gnutls_pkcs1_rsa_verify_sig( &signature, tbs, issuer->params[1], issuer->params[0])!=0) { + gnutls_assert(); + gnutls_free_datum( tbs); + return GNUTLS_CERT_NOT_TRUSTED; + } + gnutls_free_datum(tbs); + return GNUTLS_CERT_TRUSTED; + } +fprintf(stderr, "PK: %d\n", issuer->subject_pk_algorithm); + gnutls_assert(); + return GNUTLS_CERT_INVALID; +} |