diff options
-rw-r--r-- | lib/Makefile.am | 8 | ||||
-rw-r--r-- | lib/auth_x509.c | 29 | ||||
-rw-r--r-- | lib/ext_max_record.c | 2 | ||||
-rw-r--r-- | lib/gnutls.asn (renamed from lib/pkcs1.asn) | 24 | ||||
-rw-r--r-- | lib/gnutls_buffers.c | 28 | ||||
-rw-r--r-- | lib/gnutls_cert.c | 367 | ||||
-rw-r--r-- | lib/gnutls_cert.h | 28 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 1 | ||||
-rw-r--r-- | lib/gnutls_errors_int.h | 5 | ||||
-rw-r--r-- | lib/gnutls_extensions.c | 1 | ||||
-rw-r--r-- | lib/gnutls_global.c | 12 | ||||
-rw-r--r-- | lib/gnutls_global.h | 2 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 6 | ||||
-rw-r--r-- | lib/gnutls_int.h | 4 | ||||
-rw-r--r-- | lib/gnutls_pk.c | 329 | ||||
-rw-r--r-- | lib/gnutls_pk.h | 4 | ||||
-rw-r--r-- | lib/gnutls_privkey.c | 155 | ||||
-rw-r--r-- | lib/gnutls_privkey.h | 3 | ||||
-rw-r--r-- | lib/gnutls_sig.c | 86 | ||||
-rw-r--r-- | lib/pkix.asn | 5 | ||||
-rw-r--r-- | lib/x509_sig_check.c | 13 |
21 files changed, 903 insertions, 209 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index ff816415de..552d16acc3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,7 +4,7 @@ bin_SCRIPTS = libgnutls-config m4datadir = $(datadir)/aclocal m4data_DATA = libgnutls.m4 -EXTRA_DIST = debug.h gnutls_compress.h defines.h pkcs1.asn pkix.asn \ +EXTRA_DIST = debug.h gnutls_compress.h defines.h gnutls.asn pkix.asn \ gnutls_cipher.h gnutls_buffers.h gnutls_errors.h gnutls_int.h \ gnutls_handshake.h gnutls_num.h gnutls_algorithms.h gnutls_dh.h \ gnutls_kx.h gnutls_hash_int.h gnutls_cipher_int.h gnutls_db.h \ @@ -34,7 +34,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c \ gnutls_datum.c auth_rsa.c gnutls_session_pack.c \ gnutls_gcry.c gnutls_pk.c gnutls_cert.c x509_verify.c\ gnutls_global.c gnutls_privkey.c gnutls_constate.c gnutls_anon_cred.c \ - x509_sig_check.c pkix_asn1_tab.c pkcs1_asn1_tab.c gnutls_mem.c \ + x509_sig_check.c pkix_asn1_tab.c gnutls_asn1_tab.c gnutls_mem.c \ x509_extensions.c auth_x509.c gnutls_ui.c gnutls_sig.c auth_dhe_rsa.c \ gnutls_dh_primes.c ext_max_record.c gnutls_alert.c gnutls_int_compat.c \ gnutls_str.c @@ -49,8 +49,8 @@ libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) pkix_asn1_tab.c: pkix.asn -../src/asn1c pkix.asn pkix_asn1_tab.c -pkcs1_asn1_tab.c: pkcs1.asn - -../src/asn1c pkcs1.asn pkcs1_asn1_tab.c +gnutls_asn1_tab.c: gnutls.asn + -../src/asn1c gnutls.asn gnutls_asn1_tab.c gnutls-api.tex: $(COBJECTS) @echo "\\newpage" > gnutls-api.tex diff --git a/lib/auth_x509.c b/lib/auth_x509.c index 0e2ae0a39c..fafed43535 100644 --- a/lib/auth_x509.c +++ b/lib/auth_x509.c @@ -607,16 +607,15 @@ int _gnutls_proc_x509_server_certificate(GNUTLS_STATE state, opaque * data, return 0; } - -#ifdef DEBUG -# warning CHECK FOR DSS -#endif - -#define RSA_SIGN 1 +enum CertificateSigType { RSA_SIGN=1, DSA_SIGN=2 }; +/* Checks if we support the given signature algorithm + * (RSA or DSA). Returns 0 if true. + */ int _gnutls_check_supported_sign_algo(uint8 algo) { switch (algo) { case RSA_SIGN: + case DSA_SIGN: return 0; } @@ -653,7 +652,7 @@ int _gnutls_proc_x509_cert_req(GNUTLS_STATE state, opaque * data, size = p[0]; p += 1; - /* FIXME: Add support for DSS certificates too + /* check if the sign algorithm is supported. */ found = 0; for (i = 0; i < size; i++, p++) { @@ -674,6 +673,9 @@ int _gnutls_proc_x509_cert_req(GNUTLS_STATE state, opaque * data, return 0; } + /* now we ask the user to tell which one + * he wants to use. + */ DECR_LEN(dsize, size); if ((ret = _gnutls_find_acceptable_client_cert(state, p, size, @@ -782,7 +784,7 @@ int _gnutls_proc_x509_client_cert_vrfy(GNUTLS_STATE state, opaque * data, return 0; } -#define CERTTYPE_SIZE 2 +#define CERTTYPE_SIZE 3 int _gnutls_gen_x509_server_cert_req(GNUTLS_STATE state, opaque ** data) { const GNUTLS_X509PKI_CREDENTIALS cred; @@ -814,10 +816,9 @@ int _gnutls_gen_x509_server_cert_req(GNUTLS_STATE state, opaque ** data) } pdata[0] = CERTTYPE_SIZE - 1; -#ifdef DEBUG -# warning CHECK HERE FOR DSS -#endif - pdata[1] = RSA_SIGN; /* only this for now */ + + pdata[1] = RSA_SIGN; + pdata[2] = DSA_SIGN; /* only these for now */ pdata += CERTTYPE_SIZE; WRITEdatum16(pdata, cred->rdn_sequence); @@ -848,6 +849,7 @@ int _gnutls_find_apr_cert(GNUTLS_STATE state, gnutls_cert ** apr_cert_list, return GNUTLS_E_INSUFICIENT_CRED; } + if (state->security_parameters.entity == GNUTLS_SERVER) { if (cred->ncerts == 0) { @@ -882,6 +884,9 @@ int _gnutls_find_apr_cert(GNUTLS_STATE state, gnutls_cert ** apr_cert_list, /* it is allowed not to have a certificate */ } else { + /* we had already decided which certificate + * to send. + */ ind = state->gnutls_internals. client_certificate_index; diff --git a/lib/ext_max_record.c b/lib/ext_max_record.c index b33adf809e..1ffef22004 100644 --- a/lib/ext_max_record.c +++ b/lib/ext_max_record.c @@ -38,8 +38,6 @@ int _gnutls_max_record_recv_params( GNUTLS_STATE state, const opaque* data, int if (state->security_parameters.entity == GNUTLS_SERVER) { if (data_size > 0) { - gnutls_assert(); - if ( data_size != 1) { gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; diff --git a/lib/pkcs1.asn b/lib/gnutls.asn index d04dacabbc..da195bfec6 100644 --- a/lib/pkcs1.asn +++ b/lib/gnutls.asn @@ -1,11 +1,11 @@ -PKCS-1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) modules(0) pkcs-1(1)} +GNUTLS { 0 } DEFINITIONS EXPLICIT TAGS ::= BEGIN - --- Main structures +-- This file contains parts of PKCS-1 structures and some stuff +-- required for DSA keys. RSAPublicKey ::= SEQUENCE { modulus INTEGER, -- n @@ -60,5 +60,21 @@ DigestAlgorithmIdentifier ::= AlgorithmIdentifier Digest ::= OCTET STRING +DSAPublicKey ::= INTEGER + +DSAParameters ::= SEQUENCE { + p INTEGER, + q INTEGER, + g INTEGER +} + +DSAPrivateKey ::= SEQUENCE { + version INTEGER, -- should be zero + p INTEGER, + q INTEGER, + g INTEGER, + Y INTEGER, -- public + priv INTEGER +} -END
\ No newline at end of file +END diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index c821a1ba02..aec196d0a2 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -160,7 +160,7 @@ int _gnutls_record_buffer_get(ContentType type, GNUTLS_STATE state, char *data, memcpy(data, state->gnutls_internals.application_data_buffer.data, length); /* overwrite buffer */ - memcpy(state->gnutls_internals.application_data_buffer.data, + memmove(state->gnutls_internals.application_data_buffer.data, &state->gnutls_internals.application_data_buffer.data[length], state->gnutls_internals.application_data_buffer.size); state->gnutls_internals.application_data_buffer.data = @@ -179,7 +179,7 @@ int _gnutls_record_buffer_get(ContentType type, GNUTLS_STATE state, char *data, memcpy(data, state->gnutls_internals.handshake_data_buffer.data, length); /* overwrite buffer */ - memcpy(state->gnutls_internals.handshake_data_buffer.data, + memmove(state->gnutls_internals.handshake_data_buffer.data, &state->gnutls_internals.handshake_data_buffer.data[length], state->gnutls_internals.handshake_data_buffer.size); state->gnutls_internals.handshake_data_buffer.data = @@ -902,18 +902,22 @@ int _gnutls_handshake_buffer_get( GNUTLS_STATE state, char *data, int length) state->gnutls_internals.handshake_hash_buffer.size -= length; memcpy(data, state->gnutls_internals.handshake_hash_buffer.data, length); /* overwrite buffer */ - memcpy(state->gnutls_internals.handshake_hash_buffer.data, - &state->gnutls_internals.handshake_hash_buffer.data[length], - state->gnutls_internals.handshake_hash_buffer.size); - state->gnutls_internals.handshake_hash_buffer.data = - gnutls_realloc_fast(state->gnutls_internals.handshake_hash_buffer.data, - state->gnutls_internals.handshake_hash_buffer.size); + + if (state->gnutls_internals.handshake_hash_buffer.size > 0) { + memmove(state->gnutls_internals.handshake_hash_buffer.data, + &state->gnutls_internals.handshake_hash_buffer.data[length], + state->gnutls_internals.handshake_hash_buffer.size); - if (state->gnutls_internals.handshake_hash_buffer.data == NULL) { - gnutls_assert(); - return GNUTLS_E_MEMORY_ERROR; - } + state->gnutls_internals.handshake_hash_buffer.data = + gnutls_realloc_fast(state->gnutls_internals.handshake_hash_buffer.data, + state->gnutls_internals.handshake_hash_buffer.size); + if (state->gnutls_internals.handshake_hash_buffer.data == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + } + return length; } diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index bfc8d0a861..f4e4fef452 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Nikos Mavroyanopoulos + * Copyright (C) 2001,2002 Nikos Mavroyanopoulos * * This file is part of GNUTLS. * @@ -35,10 +35,6 @@ #include <gnutls_dh.h> #include <gnutls_str.h> -#ifdef DEBUG -# warning MAX ALGORITHM PARAMS == 2, ok for RSA -#endif - /* KX mappings to PK algorithms */ typedef struct { KXAlgorithm kx_algorithm; @@ -75,6 +71,29 @@ PKAlgorithm _gnutls_map_pk_get_pk(KXAlgorithm kx_algorithm) return ret; } +/* this function reads an integer + * from asn1 structs. Combines the read and mpi_scan + * steps. + */ +static +int _gnutls_x509_read_int( node_asn* node, char* value, char* tmpstr, int tmpstr_size, MPI* ret_mpi) { +int len, result; + + len = tmpstr_size - 1; + result = asn1_read_value(node, value, tmpstr, &len); + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( ret_mpi, tmpstr, &len) != 0) { + gnutls_assert(); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + return 0; +} + void gnutls_free_cert(gnutls_cert cert) { int n, i; @@ -270,16 +289,27 @@ static int read_ca_mem(GNUTLS_X509PKI_CREDENTIALS res, const char *ca, int ca_si /* Reads a PEM encoded PKCS-1 RSA private key from memory + * 2002-01-26: Added ability to read DSA keys. */ static int read_key_mem(GNUTLS_X509PKI_CREDENTIALS res, const char *key, int key_size) { int siz, ret; opaque *b64; gnutls_datum tmp; + PKAlgorithm pk; /* read PKCS-1 private key */ siz = key_size; + + /* If we find the "DSA PRIVATE" string in the + * pem encoded certificate then it's a DSA key. + */ + if (strstr( key, "DSA PRIVATE")!=NULL) + pk = GNUTLS_PK_DSA; + else + pk = GNUTLS_PK_RSA; + siz = _gnutls_fbase64_decode(key, siz, &b64); if (siz < 0) { @@ -290,14 +320,27 @@ static int read_key_mem(GNUTLS_X509PKI_CREDENTIALS res, const char *key, int key tmp.data = b64; tmp.size = siz; - if ((ret = - _gnutls_pkcs1key2gnutlsKey(&res->pkey[res->ncerts], - tmp)) < 0) { - gnutls_assert(); - gnutls_free(b64); - return ret; + + switch (pk) { /* decode the key */ + case GNUTLS_PK_RSA: + if ((ret = + _gnutls_PKCS1key2gnutlsKey(&res->pkey[res->ncerts], + tmp)) < 0) { + gnutls_assert(); + gnutls_free(b64); + return ret; + } + break; + case GNUTLS_PK_DSA: + if ((ret = + _gnutls_DSAkey2gnutlsKey(&res->pkey[res->ncerts], + tmp)) < 0) { + gnutls_assert(); + gnutls_free(b64); + return ret; + } + break; } - gnutls_free(b64); return 0; @@ -413,6 +456,18 @@ int gnutls_x509pki_allocate_sc(GNUTLS_X509PKI_CREDENTIALS * res, int ncerts) return 0; } +/* returns error if the certificate has different algorithm than + * the given key parameters. + */ +static int _gnutls_check_key_cert_match( GNUTLS_X509PKI_CREDENTIALS res) { + if (res->pkey->pk_algorithm != res->cert_list[0]->subject_pk_algorithm) { + gnutls_assert(); + return GNUTLS_E_CERTIFICATE_KEY_MISMATCH; + } + return 0; +} + + /** * gnutls_x509pki_set_key_file - Used to set keys in a GNUTLS_X509PKI_CREDENTIALS structure * @res: is an &GNUTLS_X509PKI_CREDENTIALS structure. @@ -425,7 +480,7 @@ int gnutls_x509pki_allocate_sc(GNUTLS_X509PKI_CREDENTIALS * res, int ncerts) * more than once (in case multiple keys/certificates exist for the * server). * - * Currently only PKCS-1 PEM encoded RSA private keys are accepted by + * Currently only PKCS-1 PEM encoded RSA and DSA private keys are accepted by * this function. * **/ @@ -442,6 +497,11 @@ int gnutls_x509pki_set_key_file(GNUTLS_X509PKI_CREDENTIALS res, char *CERTFILE, if ((ret = read_cert_file(res, CERTFILE)) < 0) return ret; + if ((ret=_gnutls_check_key_cert_match( res)) < 0) { + gnutls_assert(); + return ret; + } + return 0; } @@ -575,18 +635,23 @@ int gnutls_x509pki_set_key_mem(GNUTLS_X509PKI_CREDENTIALS res, const gnutls_datu if ((ret = read_cert_mem( res, CERT->data, CERT->size)) < 0) return ret; + if ((ret=_gnutls_check_key_cert_match( res)) < 0) { + gnutls_assert(); + return ret; + } + return 0; } static int _read_rsa_params(opaque * der, int dersize, MPI * params) { - opaque str[MAX_X509_CERT_SIZE]; - int len, result; + opaque str[MAX_PARAMETER_SIZE]; + int result; node_asn *spk; if (asn1_create_structure - (_gnutls_get_pkcs(), "PKCS-1.RSAPublicKey", &spk, + (_gnutls_get_gnutls_asn(), "GNUTLS.RSAPublicKey", &spk, "rsa_public_key") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; @@ -600,36 +665,83 @@ static int _read_rsa_params(opaque * der, int dersize, MPI * params) return GNUTLS_E_ASN1_PARSING_ERROR; } - len = sizeof(str) - 1; - result = asn1_read_value(spk, "rsa_public_key.modulus", str, &len); - if (result != ASN_OK) { + + if ( (result=_gnutls_x509_read_int( spk, "rsa_public_key.modulus", + str, sizeof(str)-1, ¶ms[0])) < 0) { gnutls_assert(); asn1_delete_structure(spk); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (_gnutls_mpi_scan(¶ms[0], str, &len) != 0) { + if ( (result=_gnutls_x509_read_int( spk, "rsa_public_key.publicExponent", + str, sizeof(str)-1, ¶ms[1])) < 0) { gnutls_assert(); + _gnutls_mpi_release(¶ms[0]); asn1_delete_structure(spk); - return GNUTLS_E_MPI_SCAN_FAILED; + return GNUTLS_E_ASN1_PARSING_ERROR; } - len = sizeof(str) - 1; - result = - asn1_read_value(spk, "rsa_public_key.publicExponent", str, - &len); + asn1_delete_structure(spk); + + return 0; + +} + + +/* reads p,q and g + * from the certificate + * params[0-2] + */ +static int _read_dsa_params(opaque * der, int dersize, MPI * params) +{ + opaque str[MAX_PARAMETER_SIZE]; + int result; + node_asn *spk; + + if (asn1_create_structure + (_gnutls_get_pkix(), "PKIX1Implicit88.Dss-Parms", &spk, + "dsa_parms") != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_get_der(spk, der, dersize); + if (result != ASN_OK) { gnutls_assert(); - _gnutls_mpi_release(¶ms[0]); asn1_delete_structure(spk); return GNUTLS_E_ASN1_PARSING_ERROR; } - if (_gnutls_mpi_scan(¶ms[1], str, &len) != 0) { + /* FIXME: If the parameters are not included in the certificate + * then the issuer's parameters should be used. + */ + + /* Read p */ + + if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.p", str, sizeof(str)-1, ¶ms[0])) < 0) { + gnutls_assert(); + asn1_delete_structure(spk); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + /* Read q */ + + if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.q", str, sizeof(str)-1, ¶ms[1])) < 0) { gnutls_assert(); + asn1_delete_structure(spk); _gnutls_mpi_release(¶ms[0]); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + /* Read g */ + + if ( (result=_gnutls_x509_read_int( spk, "dsa_parms.g", str, sizeof(str)-1, ¶ms[2])) < 0) { + gnutls_assert(); asn1_delete_structure(spk); - return GNUTLS_E_MPI_SCAN_FAILED; + _gnutls_mpi_release(¶ms[0]); + _gnutls_mpi_release(¶ms[1]); + return GNUTLS_E_ASN1_PARSING_ERROR; } asn1_delete_structure(spk); @@ -638,6 +750,46 @@ static int _read_rsa_params(opaque * der, int dersize, MPI * params) } +/* reads DSA's Y + * from the certificate + * params[3] + */ +static int _read_dsa_pubkey(opaque * der, int dersize, MPI * params) +{ + opaque str[MAX_PARAMETER_SIZE]; + int result; + node_asn *spk; + + if ( (result=asn1_create_structure + (_gnutls_get_gnutls_asn(), "GNUTLS.DSAPublicKey", &spk, + "dsa_public_key")) != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + result = asn1_get_der(spk, der, dersize); + + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(spk); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + /* Read p */ + + if ( (result=_gnutls_x509_read_int( spk, "dsa_public_key", str, sizeof(str)-1, ¶ms[3])) < 0) { + gnutls_assert(); + asn1_delete_structure(spk); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + asn1_delete_structure(spk); + + return 0; + +} + + #define _READ(a, aa, b, c, d, e, res, f) \ result = _IREAD(a, aa, sizeof(aa), b, c, d, e, res, sizeof(res)-1, f); \ if (result<0) return result; \ @@ -898,9 +1050,113 @@ int _gnutls_get_version(node_asn * c2, char *root) return (int) gversion[0] + 1; } -#ifdef DEBUG -# warning FIX THIS FOR DSS -#endif + +/* Extracts DSA and RSA parameters from a certificate. + */ +static +int _gnutls_extract_cert_mpi_params( const char* ALGO_OID, gnutls_cert * gCert, + node_asn* c2, char* tmpstr, int tmpstr_size) { +int len, result; + + if (strcmp( ALGO_OID, "1 2 840 113549 1 1 1") == 0) { /* pkix-1 1 - RSA */ + /* params[0] is the modulus, + * params[1] is the exponent + */ + gCert->subject_pk_algorithm = GNUTLS_PK_RSA; + + len = tmpstr_size - 1; + result = + asn1_read_value + (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", + tmpstr, &len); + + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if ((sizeof(gCert->params) / sizeof(MPI)) < RSA_PARAMS) { + gnutls_assert(); + /* internal error. Increase the MPIs in params */ + return GNUTLS_E_INTERNAL; + } + + if ((result = + _read_rsa_params(tmpstr, len / 8, gCert->params)) < 0) { + gnutls_assert(); + return result; + } + + return 0; + } + + if (strcmp( ALGO_OID, "1 2 840 10040 4 1") == 0) { /* pkix-1 1 - DSA */ + /* params[0] is p, + * params[1] is q, + * params[2] is q, + * params[3] is pub. + */ + gCert->subject_pk_algorithm = GNUTLS_PK_DSA; + + len = tmpstr_size - 1; + result = + asn1_read_value + (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", + tmpstr, &len); + + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if ((sizeof(gCert->params) / sizeof(MPI)) < DSA_PARAMS) { + gnutls_assert(); + /* internal error. Increase the MPIs in params */ + return GNUTLS_E_INTERNAL; + } + + if ((result = + _read_dsa_pubkey(tmpstr, len / 8, gCert->params)) < 0) { + gnutls_assert(); + return result; + } + + /* Now read the parameters + */ + len = tmpstr_size - 1; + result = + asn1_read_value + (c2, "certificate2.tbsCertificate.subjectPublicKeyInfo.algorithm.parameters", + tmpstr, &len); + + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if ((result = + _read_dsa_params(tmpstr, len, gCert->params)) < 0) { + gnutls_assert(); + return result; + } + + return 0; + } + + + + /* other types like DH + * currently not supported + */ + gnutls_assert(); + + _gnutls_log("CERT: ALGORITHM: %s\n", ALGO_OID); + + gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN; + + return GNUTLS_E_INVALID_PARAMETERS; +} + /* This function will convert a der certificate, to a format * (structure) that gnutls can understand and use. Actually the @@ -958,52 +1214,11 @@ int _gnutls_cert2gnutlsCert(gnutls_cert * gCert, gnutls_datum derCert) return GNUTLS_E_ASN1_PARSING_ERROR; } - if (strcmp(str, "1 2 840 113549 1 1 1") == 0) { /* pkix-1 1 - RSA */ - /* params[0] is the modulus, - * params[1] is the exponent - */ - gCert->subject_pk_algorithm = GNUTLS_PK_RSA; - - len = sizeof(str) - 1; - result = - asn1_read_value - (c2, - "certificate2.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", - str, &len); - - if (result != ASN_OK) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return GNUTLS_E_ASN1_PARSING_ERROR; - } - - if ((sizeof(gCert->params) / sizeof(MPI)) < 2) { - gnutls_assert(); - /* internal error. Increase the MPIs in params */ - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return GNUTLS_E_UNKNOWN_ERROR; - } - - if ((result = - _read_rsa_params(str, len / 8, gCert->params)) < 0) { - gnutls_assert(); - asn1_delete_structure(c2); - gnutls_free_datum( &gCert->raw); - return result; - } - - } else { - /* other types like DH, DSA - * currently not supported - */ + if ( (result=_gnutls_extract_cert_mpi_params( str, gCert, c2, str, sizeof(str))) < 0) { gnutls_assert(); - - _gnutls_log("CERT: ALGORITHM: %s\n", str); - - gCert->subject_pk_algorithm = GNUTLS_PK_UNKNOWN; - + asn1_delete_structure(c2); + gnutls_free_datum( &gCert->raw); + return result; } len = sizeof(gCert->signature); diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h index b2ab12a3cd..a94854caf0 100644 --- a/lib/gnutls_cert.h +++ b/lib/gnutls_cert.h @@ -5,12 +5,30 @@ #include <x509_asn1.h> #include <gnutls_ui.h> -#define MAX_PARAMS_SIZE 2 /* ok for RSA */ +#define MAX_PARAMS_SIZE 5 /* ok for RSA and DSA */ + +/* parameters should not be larger than this limit */ +#define MAX_PARAMETER_SIZE 1200 +#define DSA_PARAMS 5 +#define RSA_PARAMS 2 + +#if MAX_PARAMS_SIZE - RSA_PARAMS < 0 +# error INCREASE RSA_PARAMS +#endif + +#if MAX_PARAMS_SIZE - DSA_PARAMS < 0 +# error INCREASE DSA_PARAMS +#endif + typedef struct gnutls_cert { MPI params[MAX_PARAMS_SIZE]; /* the size of params depends on the public * key algorithm * RSA: [0] is modulus * [1] is public exponent + * DSA: [0] is p + * [1] is q + * [2] is g + * [3] is pub */ PKAlgorithm subject_pk_algorithm; @@ -39,6 +57,14 @@ typedef struct { MPI params[MAX_PARAMS_SIZE];/* the size of params depends on the public * key algorithm */ + /* + * DSA: [0] is p + * [1] is q + * [2] is g + * [3] is Y (public) + * [4] is priv + */ + PKAlgorithm pk_algorithm; gnutls_datum raw; /* the raw key */ diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 3a01bdf382..eafdb213e1 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -41,6 +41,7 @@ static gnutls_error_entry error_algorithms[] = { GNUTLS_ERROR_ENTRY( GNUTLS_E_MAC_FAILED, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_UNKNOWN_CIPHER, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_UNKNOWN_CIPHER_SUITE, 1), + GNUTLS_ERROR_ENTRY( GNUTLS_E_CERTIFICATE_KEY_MISMATCH, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_UNKNOWN_MAC_ALGORITHM, 1), GNUTLS_ERROR_ENTRY( GNUTLS_E_UNKNOWN_ERROR, 1), diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h index ba7686ae75..6b1d64ea11 100644 --- a/lib/gnutls_errors_int.h +++ b/lib/gnutls_errors_int.h @@ -58,8 +58,9 @@ #define GNUTLS_E_ILLEGAL_PARAMETER -55 /* GNUTLS_A_ILLEGAL_PARAMETER */ #define GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE -56 #define GNUTLS_E_PKCS1_WRONG_PAD -57 -#define GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION -57 -#define GNUTLS_E_INTERNAL -58 +#define GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION -58 +#define GNUTLS_E_INTERNAL -59 +#define GNUTLS_E_CERTIFICATE_KEY_MISMATCH -60 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -250 diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c index fb495c4729..47ef73f2ef 100644 --- a/lib/gnutls_extensions.c +++ b/lib/gnutls_extensions.c @@ -161,7 +161,6 @@ static void _gnutls_extension_list_add( GNUTLS_STATE state, uint8 type) { } else { #ifdef DEBUG _gnutls_log("EXT: Increase MAX_EXT_TYPES\n"); - exit(1); #endif } } diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 019d57db1b..50acbf63ed 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -25,7 +25,7 @@ /* created by asn1c */ -extern const static_asn pkcs1_asn1_tab[]; +extern const static_asn gnutls_asn1_tab[]; extern const static_asn pkix_asn1_tab[]; @@ -35,14 +35,14 @@ typedef void (*LOG_FUNC)( const char*); LOG_FUNC _gnutls_log_func; static node_asn *PKIX1_ASN; -static node_asn *PKCS1_ASN; +static node_asn *GNUTLS_ASN; node_asn* _gnutls_get_pkix(void) { return PKIX1_ASN; } -node_asn* _gnutls_get_pkcs(void) { - return PKCS1_ASN; +node_asn* _gnutls_get_gnutls_asn(void) { + return GNUTLS_ASN; } @@ -108,7 +108,7 @@ int gnutls_global_init( void) return GNUTLS_E_ASN1_PARSING_ERROR; } - result=asn1_create_tree( (void*)pkcs1_asn1_tab, &PKCS1_ASN); + result=asn1_create_tree( (void*)gnutls_asn1_tab, &GNUTLS_ASN); if (result != ASN_OK) { asn1_delete_structure( PKIX1_ASN); return GNUTLS_E_PARSING_ERROR; @@ -135,7 +135,7 @@ void gnutls_global_deinit( void) { _gnutls_init--; if (_gnutls_init==0) { - asn1_delete_structure( PKCS1_ASN); + asn1_delete_structure( GNUTLS_ASN); asn1_delete_structure( PKIX1_ASN); _gnutls_dh_clear_mpis(); diff --git a/lib/gnutls_global.h b/lib/gnutls_global.h index c767b45f96..6361efb781 100644 --- a/lib/gnutls_global.h +++ b/lib/gnutls_global.h @@ -4,7 +4,7 @@ #include <x509_asn1.h> int gnutls_is_secure_memory(const void* mem); -node_asn* _gnutls_get_pkcs(void); +node_asn* _gnutls_get_gnutls_asn(void); node_asn* _gnutls_get_pkix(void); #endif diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index 1b8a2ff070..785d40d315 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -359,7 +359,11 @@ opaque * data; /* We check if there are pending data to hash. */ siz = _gnutls_handshake_buffer_get_size(state); - + if (siz < 0) { + gnutls_assert(); + return siz; + } + if (siz > 0) { /* if there are data to hash */ data = gnutls_malloc(siz); if (data == NULL) { diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 7a47d88d7b..631997ac8e 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -31,9 +31,9 @@ #define WRITE_DEBUG #define READ_DEBUG #define HANDSHAKE_DEBUG // Prints some information on handshake -#define RECORD_DEBUG +#define RECORD_DEBUG*/ #define DEBUG -*/ + /* It might be a good idea to replace int with void* * here. diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index a906547917..a7a27cb80f 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -29,13 +29,17 @@ #include <gnutls_datum.h> #include "debug.h" +static int _gnutls_pk_sign(int algo, MPI* data, MPI hash, MPI ** pkey); +static int _gnutls_pk_verify(int algo, MPI hash, MPI** data, MPI **pkey); + /* Do PKCS-1 RSA encryption. * pkey is the public key and n the modulus. */ -int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, - MPI pkey, MPI n, int btype) +int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, + gnutls_datum plaintext, MPI pkey, MPI n, + int btype) { int k, psize, i, ret; MPI m, res; @@ -64,30 +68,30 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, psize = k - 3 - plaintext.size; ps = &edata[2]; - switch(btype) { - case 2: + switch (btype) { + case 2: _gnutls_get_random(ps, psize, GNUTLS_WEAK_RANDOM); for (i = 0; i < psize; i++) { if (ps[i] == 0) ps[i] = 0xff; } break; - case 1: + case 1: for (i = 0; i < psize; i++) ps[i] = 0xff; - break; + break; #ifdef ALLOW_BLOCK_0 - case 0: + case 0: for (i = 0; i < psize; i++) { ps[i] = 0x00; } - break; + break; #endif - default: - gnutls_assert(); - return GNUTLS_E_UNKNOWN_ERROR; + default: + gnutls_assert(); + return GNUTLS_E_UNKNOWN_ERROR; } - + ps[psize] = 0; memcpy(&ps[psize + 1], plaintext.data, plaintext.size); @@ -108,7 +112,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, return ret; } - _gnutls_mpi_print( NULL, &psize, res); + _gnutls_mpi_print(NULL, &psize, res); ciphertext->data = gnutls_malloc(psize); if (ciphertext->data == NULL) { @@ -116,7 +120,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, _gnutls_mpi_release(&res); return GNUTLS_E_MEMORY_ERROR; } - _gnutls_mpi_print( ciphertext->data, &psize, res); + _gnutls_mpi_print(ciphertext->data, &psize, res); ciphertext->size = psize; _gnutls_mpi_release(&res); @@ -129,8 +133,9 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext, * pkey is the private key and n the modulus. * Can decrypt block type 1 and type packets. */ -int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext, - MPI pkey, MPI n, int btype) +int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, + gnutls_datum ciphertext, MPI pkey, MPI n, + int btype) { int k, esize, i, ret; MPI c, res; @@ -162,14 +167,14 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext return ret; } - _gnutls_mpi_print( NULL, &esize, res); - edata = gnutls_malloc(esize+1); + _gnutls_mpi_print(NULL, &esize, res); + edata = gnutls_malloc(esize + 1); if (edata == NULL) { gnutls_assert(); _gnutls_mpi_release(&res); return GNUTLS_E_MEMORY_ERROR; } - _gnutls_mpi_print( &edata[1], &esize, res); + _gnutls_mpi_print(&edata[1], &esize, res); _gnutls_mpi_release(&res); @@ -188,8 +193,8 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext } ret = GNUTLS_E_DECRYPTION_FAILED; - switch(btype) { - case 2: + switch (btype) { + case 2: for (i = 2; i < esize; i++) { if (edata[i] == 0) { ret = 0; @@ -197,7 +202,7 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext } } break; - case 1: + case 1: for (i = 2; i < esize; i++) { if (edata[i] == 0 && i > 2) { ret = 0; @@ -208,30 +213,144 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext break; } } - break; - default: - gnutls_assert(); - return GNUTLS_E_UNKNOWN_ERROR; + break; + default: + gnutls_assert(); + return GNUTLS_E_UNKNOWN_ERROR; } i++; - + if (ret < 0) { gnutls_assert(); gnutls_free(edata); return GNUTLS_E_DECRYPTION_FAILED; } - - if (gnutls_sset_datum( plaintext, &edata[i], esize - i) < 0) { + + if (gnutls_sset_datum(plaintext, &edata[i], esize - i) < 0) { gnutls_assert(); gnutls_free(edata); return GNUTLS_E_MEMORY_ERROR; } - + gnutls_free(edata); return 0; } + +int _gnutls_rsa_verify( const gnutls_datum* vdata, const gnutls_datum *ciphertext, + MPI pkey, MPI n, int btype) { + + gnutls_datum plain; + int ret; + + /* decrypt signature */ + if ( (ret=_gnutls_pkcs1_rsa_decrypt( &plain, *ciphertext, pkey, n, btype)) < 0) { + gnutls_assert(); + return ret; + } + + if (plain.size != vdata->size) { + gnutls_assert(); + gnutls_sfree_datum( &plain); + return GNUTLS_E_PK_SIGNATURE_FAILED; + } + + if ( memcmp(plain.data, vdata->data, plain.size)!=0) { + gnutls_assert(); + gnutls_sfree_datum( &plain); + return GNUTLS_E_PK_SIGNATURE_FAILED; + } + + gnutls_sfree_datum( &plain); + + return 0; /* ok */ +} + + +/* Do DSA signature calculation + */ +int _gnutls_dsa_sign(gnutls_datum * signature, gnutls_datum plaintext, + MPI p, MPI q, MPI g, MPI y) +{ + MPI res[2], mdata; + int sig_size; + MPI *_pkey[DSA_PARAMS]; + int k, ret, psize; + + k = plaintext.size; + if (_gnutls_mpi_scan(&mdata, plaintext.data, &k) != 0) { + gnutls_assert(); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + _pkey[0] = &p; + _pkey[1] = &q; + _pkey[2] = &g; + _pkey[3] = &y; + ret = _gnutls_pk_sign(GCRY_PK_DSA, res, mdata, _pkey); + /* res now holds r,s */ + _gnutls_mpi_release(&mdata); + + if (ret < 0) { + gnutls_assert(); + return ret; + } + +#error FIX r,s + + _gnutls_mpi_print(NULL, &sig_size, res[0]); + + signature->data = gnutls_malloc(sig_size); + if (signature->data == NULL) { + gnutls_assert(); + _gnutls_mpi_release(&res[0]); + return GNUTLS_E_MEMORY_ERROR; + } + _gnutls_mpi_print(signature->data, &psize, res[0]); + signature->size = psize; + + _gnutls_mpi_release(&res[0]); + + return 0; +} + +int _gnutls_dsa_verify( const gnutls_datum* vdata, const gnutls_datum *ciphertext, + MPI p, MPI q, MPI g, MPI y) { + + MPI mdata; + int ret, k; + MPI *_pkey[DSA_PARAMS]; + MPI *_data[2]; + MPI r, s; + + #error FIX r,s + + k = vdata->size; + if (_gnutls_mpi_scan(&mdata, vdata->data, &k) != 0) { + gnutls_assert(); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + /* decrypt signature */ + _pkey[0] = &p; + _pkey[1] = &q; + _pkey[2] = &g; + _pkey[3] = &y; + + _data[0] = &r; + _data[1] = &s; + if ( (ret=_gnutls_pk_verify( GCRY_PK_DSA, mdata, _data, _pkey)) < 0) { + _gnutls_mpi_release(&mdata); + gnutls_assert(); + return ret; + } + _gnutls_mpi_release(&mdata); + + return 0; /* ok */ +} + + /* this is taken from gnupg */ @@ -239,17 +358,20 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext * Emulate our old PK interface here - sometime in the future we might * change the internal design to directly fit to libgcrypt. */ -int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey) +int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI ** pkey) { GCRY_SEXP s_ciph, s_data, s_pkey; int rc; /* make a sexp from pkey */ - if (algo == GCRY_PK_RSA) { + switch (algo) { + case GCRY_PK_RSA: rc = gcry_sexp_build(&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))", *pkey[0], *pkey[1]); - } else { + break; + + default: gnutls_assert(); return GNUTLS_E_UNKNOWN_KX_ALGORITHM; } @@ -272,8 +394,8 @@ int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey) if (rc != 0) { gnutls_assert(); - return GNUTLS_E_UNKNOWN_ERROR; - + return GNUTLS_E_PK_ENCRYPTION_FAILED; + } else { /* add better error handling or make gnupg use S-Exp directly */ GCRY_SEXP list = gcry_sexp_find_token(s_ciph, "a", 0); if (list == NULL) { @@ -295,3 +417,140 @@ int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey) gcry_sexp_release(s_ciph); return rc; } + +/* in case of DSA puts into data, r,s + */ +static +int _gnutls_pk_sign(int algo, MPI* data, MPI hash, MPI ** pkey) +{ + GCRY_SEXP s_hash, s_key, s_sig; + int rc; + + /* make a sexp from pkey */ + switch (algo) { + case GCRY_PK_DSA: + rc = gcry_sexp_build(&s_key, NULL, + "(public-key(rsa(p%m)(q%m)(g%m)(y%m)(x%m)))", + *pkey[0], *pkey[1], *pkey[2], + *pkey[3], *pkey[4]); + break; + + default: + gnutls_assert(); + return GNUTLS_E_UNKNOWN_KX_ALGORITHM; + } + + if (rc != 0) { + gnutls_assert(); + return GNUTLS_E_INTERNAL; + } + + /* put the data into a simple list */ + if (gcry_sexp_build(&s_hash, NULL, "%m", hash)) { + gnutls_assert(); + return GNUTLS_E_UNKNOWN_ERROR; + } + + /* pass it to libgcrypt */ + rc = gcry_pk_sign(&s_sig, s_hash, s_key); + gcry_sexp_release(s_hash); + gcry_sexp_release(s_key); + + if (rc != 0) { + gnutls_assert(); + return GNUTLS_E_PK_ENCRYPTION_FAILED; + + } else { + GCRY_SEXP list = gcry_sexp_find_token( s_sig, "r" , 0); + if (list == NULL) { + gnutls_assert(); + gcry_sexp_release(s_sig); + return GNUTLS_E_INTERNAL; + } + + data[0] = gcry_sexp_nth_mpi( list, 1, 0 ); + gcry_sexp_release (list); + + list = gcry_sexp_find_token( s_sig, "s" , 0); + if (list == NULL) { + gnutls_assert(); + gcry_sexp_release(s_sig); + return GNUTLS_E_INTERNAL; + } + + data[1] = gcry_sexp_nth_mpi( list, 1, 0 ); + gcry_sexp_release (list); + + } + + gcry_sexp_release(s_sig); + return 0; +} + + +static int _gnutls_pk_verify(int algo, MPI hash, MPI** data, MPI **pkey) +{ + GCRY_SEXP s_sig, s_hash, s_pkey; + int rc; + + /* make a sexp from pkey */ + switch (algo) { + case GCRY_PK_DSA: + rc = gcry_sexp_build(&s_pkey, NULL, + "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", + pkey[0], pkey[1], pkey[2], + pkey[3]); + break; + + default: + gnutls_assert(); + return GNUTLS_E_UNKNOWN_KX_ALGORITHM; + } + + if (rc != 0) { + gnutls_assert(); + gcry_sexp_release(s_pkey); + return GNUTLS_E_INTERNAL; + } + + /* put the data into a simple list */ + if (gcry_sexp_build(&s_hash, NULL, "%m", hash)) { + gnutls_assert(); + gcry_sexp_release(s_pkey); + return GNUTLS_E_UNKNOWN_ERROR; + } + + switch (algo) { + case GCRY_PK_DSA: + rc = gcry_sexp_build(&s_sig, NULL, + "(sig-val(dsa(r%m)(s%m)))", + *data[0], *data[1]); + break; + + default: + gnutls_assert(); + gcry_sexp_release(s_pkey); + gcry_sexp_release(s_sig); + return GNUTLS_E_UNKNOWN_KX_ALGORITHM; + } + + if (rc != 0) { + gnutls_assert(); + gcry_sexp_release(s_pkey); + gcry_sexp_release(s_sig); + return GNUTLS_E_INTERNAL; + } + + rc = gcry_pk_verify( s_sig, s_hash, s_pkey ); + + gcry_sexp_release(s_sig); + gcry_sexp_release(s_hash); + gcry_sexp_release(s_pkey); + + if (rc != 0) { + gnutls_assert(); + return GNUTLS_E_PK_SIGNATURE_FAILED; + } + + return 0; +} diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index dc11a5a7ea..95a54f4ee3 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -8,7 +8,11 @@ typedef enum PKAlgorithm { GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA, /* sign only */ 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 btype); +int _gnutls_dsa_sign(gnutls_datum * signature, gnutls_datum plaintext, + MPI p, MPI q, MPI g, MPI Y); int _gnutls_pkcs1_rsa_decrypt(gnutls_datum * plaintext, gnutls_datum ciphertext, MPI pkey, MPI n, int btype); +int _gnutls_rsa_verify( const gnutls_datum* vdata, const gnutls_datum *ciphertext, + MPI pkey, MPI n, int btype); #endif /* GNUTLS_PK_H */ diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c index 3501944ede..ac749ed47b 100644 --- a/lib/gnutls_privkey.c +++ b/lib/gnutls_privkey.c @@ -30,29 +30,30 @@ #include <gnutls_gcry.h> #include <gnutls_global.h> + /* Converts an RSA PKCS#1 key to * an internal structure (gnutls_private_key) */ -int _gnutls_pkcs1key2gnutlsKey(gnutls_private_key * pkey, gnutls_datum cert) { +int _gnutls_PKCS1key2gnutlsKey(gnutls_private_key * pkey, gnutls_datum raw_key) { int result; - opaque str[MAX_X509_CERT_SIZE]; + opaque str[MAX_PARAMETER_SIZE]; int len = sizeof(str); node_asn *pkcs_asn; pkey->pk_algorithm = GNUTLS_PK_RSA; - if (asn1_create_structure( _gnutls_get_pkcs(), "PKCS-1.RSAPrivateKey", &pkcs_asn, "rsakey")!=ASN_OK) { + if (asn1_create_structure( _gnutls_get_gnutls_asn(), "GNUTLS.RSAPrivateKey", &pkcs_asn, "rsakey")!=ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } - if ((sizeof( pkey->params)/sizeof(MPI)) < 2) { + if ((sizeof( pkey->params)/sizeof(MPI)) < RSA_PARAMS) { gnutls_assert(); /* internal error. Increase the MPIs in params */ - return GNUTLS_E_UNKNOWN_ERROR; + return GNUTLS_E_INTERNAL; } - result = asn1_get_der( pkcs_asn, cert.data, cert.size); + result = asn1_get_der( pkcs_asn, raw_key.data, raw_key.size); if (result != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_PARSING_ERROR; @@ -94,9 +95,149 @@ int _gnutls_pkcs1key2gnutlsKey(gnutls_private_key * pkey, gnutls_datum cert) { asn1_delete_structure(pkcs_asn); - if (gnutls_set_datum( &pkey->raw, cert.data, cert.size) < 0) { + if (gnutls_set_datum( &pkey->raw, raw_key.data, raw_key.size) < 0) { + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + return 0; + + +} + +int _gnutls_DSAkey2gnutlsKey(gnutls_private_key * pkey, gnutls_datum raw_key) { + int result; + opaque str[MAX_PARAMETER_SIZE]; + int len = sizeof(str); + node_asn *pkix_asn; + + pkey->pk_algorithm = GNUTLS_PK_DSA; + + if (asn1_create_structure( _gnutls_get_gnutls_asn(), "GNUTLS.DSAPrivateKey", &pkix_asn, "dsakey")!=ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_ERROR; + } + + if ((sizeof( pkey->params)/sizeof(MPI)) < DSA_PARAMS) { + gnutls_assert(); + /* internal error. Increase the MPIs in params */ + return GNUTLS_E_INTERNAL; + } + + result = asn1_get_der( pkix_asn, raw_key.data, raw_key.size); + if (result != ASN_OK) { + gnutls_assert(); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + len = sizeof(str) - 1; + result = + asn1_read_value( pkix_asn, "dsakey.p", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( &pkey->params[0], /* p */ + str, &len) != 0) { + gnutls_assert(); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + len = sizeof(str) - 1; + result = + asn1_read_value( pkix_asn, "dsakey.q", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( &pkey->params[1], /* q */ str, &len) != 0) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + len = sizeof(str) - 1; + result = + asn1_read_value( pkix_asn, "dsakey.g", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( &pkey->params[2], /* g */ str, &len) != 0) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + len = sizeof(str) - 1; + result = + asn1_read_value( pkix_asn, "dsakey.Y", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + _gnutls_mpi_release(&pkey->params[2]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( &pkey->params[3], /* priv key */ + str, &len) != 0) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + _gnutls_mpi_release(&pkey->params[2]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + len = sizeof(str) - 1; + result = + asn1_read_value( pkix_asn, "dsakey.priv", str, &len); + if (result != ASN_OK) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + _gnutls_mpi_release(&pkey->params[2]); + _gnutls_mpi_release(&pkey->params[3]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_ASN1_PARSING_ERROR; + } + + if (_gnutls_mpi_scan( &pkey->params[4], /* priv key */ + str, &len) != 0) { + gnutls_assert(); + _gnutls_mpi_release(&pkey->params[0]); + _gnutls_mpi_release(&pkey->params[1]); + _gnutls_mpi_release(&pkey->params[2]); + _gnutls_mpi_release(&pkey->params[3]); + asn1_delete_structure(pkix_asn); + return GNUTLS_E_MPI_SCAN_FAILED; + } + + asn1_delete_structure(pkix_asn); + + if (gnutls_set_datum( &pkey->raw, raw_key.data, raw_key.size) < 0) { _gnutls_mpi_release(&pkey->params[0]); _gnutls_mpi_release(&pkey->params[1]); + _gnutls_mpi_release(&pkey->params[2]); + _gnutls_mpi_release(&pkey->params[3]); + _gnutls_mpi_release(&pkey->params[4]); gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } diff --git a/lib/gnutls_privkey.h b/lib/gnutls_privkey.h index 244c3084d1..4e045a01b6 100644 --- a/lib/gnutls_privkey.h +++ b/lib/gnutls_privkey.h @@ -1,2 +1,3 @@ -int _gnutls_pkcs1key2gnutlsKey(gnutls_private_key * pkey, gnutls_datum cert); +int _gnutls_PKCS1key2gnutlsKey(gnutls_private_key * pkey, gnutls_datum raw_key); +int _gnutls_DSAkey2gnutlsKey(gnutls_private_key * pkey, gnutls_datum raw_key); void _gnutls_free_private_key( gnutls_private_key pkey); diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c index 313cf6b226..a2502705f6 100644 --- a/lib/gnutls_sig.c +++ b/lib/gnutls_sig.c @@ -65,12 +65,10 @@ GNUTLS_MAC_HANDLE td_sha; dconcat.data = concat; dconcat.size = 36; - ret = _gnutls_pkcs1_rsa_generate_sig( cert, pkey, &dconcat, signature); - if (ret < 0) { + ret = _gnutls_generate_sig( cert, pkey, &dconcat, signature); + if (ret < 0) gnutls_assert(); - return ret; - } - + return ret; } @@ -113,23 +111,20 @@ opaque concat[36]; dconcat.data = concat; dconcat.size = 36; - ret = _gnutls_pkcs1_rsa_generate_sig( cert, pkey, &dconcat, signature); - - if (ret < 0) { + ret = _gnutls_generate_sig( cert, pkey, &dconcat, signature); + if (ret < 0) gnutls_assert(); - return ret; - } - + return ret; } -/* This will create a PKCS1 signature, as defined in the TLS protocol. +/* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. */ -int _gnutls_pkcs1_rsa_generate_sig( gnutls_cert* cert, gnutls_private_key *pkey, const gnutls_datum* hash_concat, gnutls_datum *signature) +int _gnutls_generate_sig( gnutls_cert* cert, gnutls_private_key *pkey, const gnutls_datum* hash_concat, gnutls_datum *signature) { int ret; gnutls_datum tmpdata; @@ -146,10 +141,28 @@ gnutls_datum tmpdata; switch(pkey->pk_algorithm) { case GNUTLS_PK_RSA: - tmpdata.data = hash_concat->data; tmpdata.size = hash_concat->size; /* md5 + sha */ + /* encrypt */ + if ((ret=_gnutls_pkcs1_rsa_encrypt( signature, tmpdata, pkey->params[0], pkey->params[1], 1)) < 0) { + gnutls_assert(); + return ret; + } + + break; + case GNUTLS_PK_DSA: + /* Ok this is silly. We have calculated + * md5 also! + */ + tmpdata.data = &hash_concat->data[16]; + tmpdata.size = 20; /* sha */ + + /* sign */ + if ((ret=_gnutls_dsa_sign( signature, tmpdata, pkey->params[0], pkey->params[1], pkey->params[2], pkey->params[3])) < 0) { + gnutls_assert(); + return ret; + } break; default: gnutls_assert(); @@ -158,18 +171,15 @@ gnutls_datum tmpdata; } - /* encrypt der */ - if ( (ret=_gnutls_pkcs1_rsa_encrypt( signature, tmpdata, pkey->params[0], pkey->params[1], 1)) < 0) { - gnutls_assert(); - return ret; - } return 0; } + + int _gnutls_pkcs1_rsa_verify_sig( gnutls_cert *cert, const gnutls_datum *hash_concat, gnutls_datum *signature) { int ret; - gnutls_datum plain, vdata; + gnutls_datum vdata; if (cert->version == 0 || cert==NULL) { /* this is the only way to check * if it is initialized @@ -193,30 +203,32 @@ int _gnutls_pkcs1_rsa_verify_sig( gnutls_cert *cert, const gnutls_datum *hash_co vdata.data = hash_concat->data; vdata.size = hash_concat->size; + /* verify signature */ + if ( (ret=_gnutls_rsa_verify( &vdata, signature, cert->params[1], cert->params[0], 1)) < 0) { + gnutls_assert(); + return ret; + } + + break; + case GNUTLS_PK_DSA: + + vdata.data = &hash_concat->data[16]; + vdata.size = 20; /* sha1 */ + + /* decrypt signature */ + if ( (ret=_gnutls_dsa_verify( &vdata, *signature, cert->params[0], + cert->params[1], cert->params[2], cert->params[3])) < 0) { + gnutls_assert(); + return ret; + } + break; default: gnutls_assert(); return GNUTLS_E_UNIMPLEMENTED_FEATURE; } - /* decrypt signature */ - if ( (ret=_gnutls_pkcs1_rsa_decrypt( &plain, *signature, cert->params[1], cert->params[0], 1)) < 0) { - gnutls_assert(); - return ret; - } - if (plain.size != vdata.size) { - gnutls_assert(); - gnutls_sfree_datum( &plain); - return GNUTLS_E_PK_SIGNATURE_FAILED; - } - - if ( memcmp(plain.data, vdata.data, plain.size)!=0) { - gnutls_assert(); - gnutls_sfree_datum( &plain); - return GNUTLS_E_PK_SIGNATURE_FAILED; - } - gnutls_sfree_datum( &plain); return 0; } diff --git a/lib/pkix.asn b/lib/pkix.asn index 183345e523..9faab3a370 100644 --- a/lib/pkix.asn +++ b/lib/pkix.asn @@ -613,9 +613,10 @@ sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 } -Dss-Sig-Value ::= SEQUENCE { +Dss-Sig-Value ::= SEQUENCE { r INTEGER, - s INTEGER } + s INTEGER +} dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) ansi-x942(10046) number-type(2) 1 } diff --git a/lib/x509_sig_check.c b/lib/x509_sig_check.c index e6f1d7f3ab..1556ed1114 100644 --- a/lib/x509_sig_check.c +++ b/lib/x509_sig_check.c @@ -81,7 +81,7 @@ int result; opaque str[1024]; int len; - if (asn1_create_structure( _gnutls_get_pkcs(), "PKCS-1.DigestInfo", &dinfo, "digest_info")!=ASN_OK) { + if (asn1_create_structure( _gnutls_get_gnutls_asn(), "GNUTLS.DigestInfo", &dinfo, "digest_info")!=ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } @@ -182,6 +182,13 @@ _pkcs1_rsa_verify_sig( gnutls_datum* signature, gnutls_datum* text, MPI e, MPI m return 0; } +#ifdef DEBUG +/* This is for CA DSS params - can wait */ +# warning CHECK HERE FOR DSS +#endif + +/* verifies if the certificate is properly signed. + */ CertificateStatus gnutls_x509_verify_signature(gnutls_cert* cert, gnutls_cert* issuer) { gnutls_datum signature; gnutls_datum tbs; @@ -218,8 +225,8 @@ static int _gnutls_digestinfo_encode( opaque* data, int data_size, char* OID, gn node_asn *di; int result; - if (asn1_create_structure( _gnutls_get_pkcs(), - "PKCS-1.DigestInfo", &di, "di") != ASN_OK) { + if (asn1_create_structure( _gnutls_get_gnutls_asn(), + "GNUTLS.DigestInfo", &di, "di") != ASN_OK) { gnutls_assert(); return GNUTLS_E_ASN1_ERROR; } |