#include <gnutls_global.h>
#include <x509_verify.h>
#include "debug.h"
+#include <gnutls_sig.h>
int gen_rsa_certificate(GNUTLS_STATE, opaque **);
+int gen_rsa_client_cert_vrfy(GNUTLS_STATE, opaque **);
int proc_rsa_cert_req(GNUTLS_STATE, opaque *, int);
int gen_rsa_client_kx(GNUTLS_STATE, opaque **);
int proc_rsa_client_kx(GNUTLS_STATE, opaque *, int);
int proc_rsa_certificate(GNUTLS_STATE, opaque *, int);
-MOD_AUTH_STRUCT rsa_auth_struct = {
+MOD_AUTH_STRUCT rsa_auth_struct =
+{
"RSA",
gen_rsa_certificate,
NULL, /* gen server kx */
NULL, /* gen server kx2 */
NULL, /* gen client kx0 */
gen_rsa_client_kx,
- NULL, /* gen client cert vrfy */
+ gen_rsa_client_cert_vrfy, /* gen client cert vrfy */
NULL,
proc_rsa_certificate,
/* This function extracts the RSA parameters from the given(?) certificate.
*/
-static int _gnutls_get_rsa_params( RSA_Params * params,
+static int _gnutls_get_rsa_params(RSA_Params * params,
MPI * mod, MPI * exp, gnutls_datum cert)
{
int ret = 0, result;
opaque str[5 * 1024];
int len = sizeof(str);
node_asn *srsa, *spk;
-
- if (asn1_create_structure( _gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &srsa, "rsa_params")
+
+ if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &srsa, "rsa_params")
!= ASN_OK) {
gnutls_assert();
return GNUTLS_E_ASN1_ERROR;
}
-
- result = asn1_get_der( srsa, cert.data, cert.size);
+ result = asn1_get_der(srsa, cert.data, cert.size);
if (result != ASN_OK) {
/* couldn't decode DER */
gnutls_assert();
return GNUTLS_E_ASN1_PARSING_ERROR;
}
-
-
len = sizeof(str) - 1;
result =
asn1_read_value
asn1_delete_structure(srsa);
return GNUTLS_E_ASN1_PARSING_ERROR;
}
-
if (!strcmp(str, "1 2 840 113549 1 1 1")) { /* pkix-1 1 - RSA */
len = sizeof(str) - 1;
result =
gnutls_assert();
return GNUTLS_E_ASN1_PARSING_ERROR;
}
-
if (asn1_create_structure
- ( _gnutls_get_pkcs(),
+ (_gnutls_get_pkcs(),
"PKCS-1.RSAPublicKey", &spk, "rsa_public_key") != ASN_OK) {
gnutls_assert();
return GNUTLS_E_ASN1_ERROR;
}
-
if (len % 8 != 0) {
gnutls_assert();
asn1_delete_structure(spk);
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
}
-
result = asn1_get_der(spk, str, len / 8);
if (result != ASN_OK) {
asn1_delete_structure(spk);
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) {
asn1_delete_structure(spk);
return GNUTLS_E_ASN1_PARSING_ERROR;
}
-
if (gcry_mpi_scan(mod, GCRYMPI_FMT_USG, str, &len) != 0) {
gnutls_assert();
asn1_delete_structure(spk);
return GNUTLS_E_MPI_SCAN_FAILED;
}
-
if (params != NULL)
if (gnutls_set_datum
(¶ms->rsa_modulus, str, len) < 0) {
asn1_delete_structure(spk);
return GNUTLS_E_MEMORY_ERROR;
}
-
len = sizeof(str) - 1;
result =
asn1_read_value(spk, "rsa_public_key.publicExponent", str, &len);
_gnutls_mpi_release(mod);
return GNUTLS_E_ASN1_PARSING_ERROR;
}
-
if (gcry_mpi_scan(exp, GCRYMPI_FMT_USG, str, &len) != 0) {
gnutls_assert();
_gnutls_mpi_release(mod);
asn1_delete_structure(spk);
return GNUTLS_E_MEMORY_ERROR;
}
-
asn1_delete_structure(spk);
ret = 0;
* to the gnutls_private_key structure.
*/
static int _gnutls_get_private_rsa_params(GNUTLS_KEY key,
- gnutls_private_key *pkey)
+ gnutls_private_key * pkey)
{
key->u = gcry_mpi_copy(pkey->params[0]);
gnutls_assert();
return GNUTLS_E_INSUFICIENT_CRED;
}
-
if (cred->ncerts == 0) {
apr_cert_list = NULL;
apr_cert_list_length = 0;
apr_pkey = NULL;
} else {
- ind = _gnutls_find_cert_list_index( cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname);
- apr_cert_list = cred->cert_list[ind];
- apr_cert_list_length = cred->cert_list_length[ind];
- apr_pkey = &cred->pkey[ind];
+ if (state->security_parameters.entity == GNUTLS_CLIENT)
+ ind = state->gnutls_internals.client_certificate_index;
+ else /* server */
+ ind = _gnutls_find_cert_list_index(cred->cert_list, cred->ncerts, state->security_parameters.extensions.dnsname);
+
+ if (ind < 0) {
+ apr_cert_list = NULL;
+ apr_cert_list_length = 0;
+ apr_pkey = NULL;
+ } else {
+ apr_cert_list = cred->cert_list[ind];
+ apr_cert_list_length = cred->cert_list_length[ind];
+ apr_pkey = &cred->pkey[ind];
+ }
}
ret = 3;
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
-
WRITEuint24(ret - 3, pdata);
pdata += 3;
for (i = 0; i < apr_cert_list_length; i++) {
/* read the rsa parameters now, since later we will
* not know which certificate we used!
*/
- if (i!=0) /* if we parsed at least one certificate */
+ if (i != 0) /* if we parsed at least one certificate */
ret = _gnutls_get_private_rsa_params(state->gnutls_key, apr_pkey);
else
ret = 0;
-
+
if (ret < 0) {
gnutls_assert();
return ret;
}
-
return pdatasize;
}
gnutls_datum ciphertext;
int ret, dsize;
- if (_gnutls_version_ssl3( gnutls_get_current_version( state)) == 0) {
+ if (_gnutls_version_ssl3(gnutls_get_current_version(state)) == 0) {
/* SSL 3.0 */
ciphertext.data = data;
ciphertext.size = data_size;
}
ret =
_gnutls_pkcs1_rsa_decrypt(&plaintext, ciphertext, state->gnutls_key->u,
- state->gnutls_key->A, 2); /* btype==2 */
+ state->gnutls_key->A, 2); /* btype==2 */
if (ret < 0) {
/* in case decryption fails then don't inform
RANDOMIZE_KEY(state->gnutls_key->key, secure_malloc);
} else {
GNUTLS_Version ver;
-
- ver = gnutls_get_current_version( state);
-
- if ( _gnutls_version_get_major( ver) != plaintext.data[0])
+
+ ver = gnutls_get_current_version(state);
+
+ if (_gnutls_version_get_major(ver) != plaintext.data[0])
ret = GNUTLS_E_DECRYPTION_FAILED;
- if ( _gnutls_version_get_minor( ver) != plaintext.data[1])
+ if (_gnutls_version_get_minor(ver) != plaintext.data[1])
ret = GNUTLS_E_DECRYPTION_FAILED;
if (ret != 0) {
_gnutls_mpi_release(&state->gnutls_key->B);
const X509PKI_CREDENTIALS cred;
int dsize = data_size;
int i, j;
- gnutls_cert* peer_certificate_list;
+ gnutls_cert *peer_certificate_list;
int peer_certificate_list_size = 0;
gnutls_datum tmp;
CertificateStatus verify;
-
+
cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
if (cred == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFICIENT_CRED;
}
-
- if (state->gnutls_key->auth_info==NULL)
+ if (state->gnutls_key->auth_info == NULL)
state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(X509PKI_CLIENT_AUTH_INFO));
if (state->gnutls_key->auth_info == NULL) {
gnutls_assert();
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
-
info = state->gnutls_key->auth_info;
i = dsize;
gnutls_assert();
return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
}
-
-
dsize = data_size;
i = dsize;
peer_certificate_list =
- gnutls_malloc( sizeof(gnutls_cert) *
- ( peer_certificate_list_size));
+ gnutls_malloc(sizeof(gnutls_cert) *
+ (peer_certificate_list_size));
- if ( peer_certificate_list == NULL) {
+ if (peer_certificate_list == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
-
p = data + 3;
i = data_size - 3;
j = 0;
tmp.size = len;
tmp.data = p;
- if ( (ret=_gnutls_cert2gnutlsCert( &peer_certificate_list[j], tmp)) < 0) {
+ if ((ret = _gnutls_cert2gnutlsCert(&peer_certificate_list[j], tmp)) < 0) {
gnutls_assert();
- gnutls_free( peer_certificate_list);
+ gnutls_free(peer_certificate_list);
return ret;
}
-
p += len;
i -= len + 3;
j++;
/* store the required parameters for the handshake
*/
if ((ret =
- _gnutls_get_rsa_params( NULL, &state->gnutls_key->A, &state->gnutls_key->u,
+ _gnutls_get_rsa_params(NULL, &state->gnutls_key->A, &state->gnutls_key->u,
peer_certificate_list[0].raw)) < 0) {
gnutls_assert();
- gnutls_free( peer_certificate_list);
+ gnutls_free(peer_certificate_list);
return ret;
}
-
-
/* Verify certificate
*/
- verify = gnutls_verify_certificate( peer_certificate_list, peer_certificate_list_size,
- cred->ca_list, cred->ncas, NULL, 0);
-
- _gnutls_copy_x509_client_auth_info( info, &peer_certificate_list[0], verify);
+ verify = gnutls_verify_certificate(peer_certificate_list, peer_certificate_list_size,
+ cred->ca_list, cred->ncas, NULL, 0);
+
+ _gnutls_copy_x509_client_auth_info(info, &peer_certificate_list[0], verify);
- gnutls_free( peer_certificate_list);
+ gnutls_free(peer_certificate_list);
return 0;
}
MPI pkey, n;
int ret;
GNUTLS_Version ver;
-
+
if (auth == NULL) {
/* this shouldn't have happened. The proc_certificate
* function should have detected that.
gnutls_assert();
return GNUTLS_E_INSUFICIENT_CRED;
}
-
RANDOMIZE_KEY(state->gnutls_key->key, secure_malloc);
-
- ver = gnutls_get_current_version( state);
-
- state->gnutls_key->key.data[0] = _gnutls_version_get_major( ver);
- state->gnutls_key->key.data[1] = _gnutls_version_get_minor( ver);
+
+ ver = gnutls_get_current_version(state);
+
+ state->gnutls_key->key.data[0] = _gnutls_version_get_major(ver);
+ state->gnutls_key->key.data[1] = _gnutls_version_get_minor(ver);
if ((ret =
_gnutls_pkcs1_rsa_encrypt(&sdata, state->gnutls_key->key, state->gnutls_key->u, state->gnutls_key->A, 2)) < 0) {
_gnutls_mpi_release(&n);
return ret;
}
-
_gnutls_mpi_release(&state->gnutls_key->A);
_gnutls_mpi_release(&state->gnutls_key->u);
- if (_gnutls_version_ssl3( ver) == 0) {
+ if (_gnutls_version_ssl3(ver) == 0) {
/* SSL 3.0 */
*data = sdata.data;
return sdata.size;
}
-#define RSA_SIGN 1
+/* Finds the appropriate certificate depending on the cA Distinguished name
+ * advertized by the server
+ */
+static int _gnutls_find_acceptable_client_cert( const X509PKI_CREDENTIALS cred, const opaque* data,
+ int data_size, int *ind) {
+node_asn *dn;
+int result, size;
+int indx = -1;
+int start, end, len, i, j;
+
+
+ do {
+
+ DECR_LEN(data_size, 2);
+ size = READuint16(data);
+ data += 2;
+
+ for(i=0;i<cred->ncerts;i++) {
+
+ for (j=0;j<cred->cert_list_length[i];j++) {
+ if (asn1_create_structure(_gnutls_get_pkix(), "PKIX1Implicit88.Certificate", &dn, "dn") != ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ result = asn1_get_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size);
+ if (result != ASN_OK) {
+ /* couldn't decode DER */
+ gnutls_assert();
+ asn1_delete_structure( dn);
+ return GNUTLS_E_ASN1_PARSING_ERROR;
+ }
+
+ result = asn1_get_start_end_der( dn, cred->cert_list[i][j].raw.data, cred->cert_list[i][j].raw.size,
+ "dn.tbsCertificate.issuer", &start, &end);
+
+ if (result != ASN_OK) {
+ /* couldn't decode DER */
+ gnutls_assert();
+ asn1_delete_structure( dn);
+ return GNUTLS_E_ASN1_PARSING_ERROR;
+ }
+ asn1_delete_structure( dn);
+
+ len = end - start + 1;
+
+ if ( len != size) continue;
+
+ if (memcmp(
+ &cred->cert_list[i][j].raw.data[start],
+ data, len) == 0 ) {
+ indx = i;
+ break;
+ }
+ }
+ if (indx != -1)
+ break;
+ }
+
+ if (indx != -1)
+ break;
+ /* move to next record */
+ data_size -= size;
+ if (data_size <= 0)
+ break;
+
+ data += size;
+
+ } while (1);
+
+ if (indx==-1 && cred->ncerts > 0) /* use the first certificate */
+ indx = 0;
+
+ *ind = indx;
+ return 0;
+}
+
+#define RSA_SIGN 1
int proc_rsa_cert_req(GNUTLS_STATE state, opaque * data, int data_size)
{
- int size;
+ int size, ret;
opaque *p = data;
const X509PKI_CREDENTIALS cred;
int dsize = data_size;
int i;
int found;
-
+ int ind;
+
cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
if (cred == NULL) {
gnutls_assert();
return GNUTLS_E_INSUFICIENT_CRED;
}
-
state->gnutls_key->certificate_requested = 1;
- if (state->gnutls_key->auth_info==NULL)
+ if (state->gnutls_key->auth_info == NULL)
state->gnutls_key->auth_info = gnutls_calloc(1, sizeof(X509PKI_CLIENT_AUTH_INFO));
if (state->gnutls_key->auth_info == NULL) {
gnutls_assert();
p += 1;
found = 0;
- for (i=0;i<size;i++,p++) {
- DECR_LEN( dsize, 1);
- if (*p==RSA_SIGN) found=1;
+ for (i = 0; i < size; i++, p++) {
+ DECR_LEN(dsize, 1);
+ if (*p == RSA_SIGN)
+ found = 1;
}
-
- if (found==0) {
+
+ if (found == 0) {
gnutls_assert();
return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
}
-
-
-
DECR_LEN(dsize, 2);
size = READuint16(p);
p += 2;
-fprintf(stderr, "DN size: %d\n", size);
if (size == 0) {
return 0;
}
-#warning "FIND CERTIFICATE TO SEND"
-//fprintf(stderr, "DN: %s\n", _gnutls_bin2hex( p, size));
+ if ( (ret = _gnutls_find_acceptable_client_cert( cred, p, size, &ind)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* put the index of the client certificate to use
+ */
+ state->gnutls_internals.client_certificate_index = ind;
return 0;
}
+
+int gen_rsa_client_cert_vrfy(GNUTLS_STATE state, opaque ** data)
+{
+ const X509PKI_CREDENTIALS cred;
+ int ret, ind;
+ gnutls_cert *apr_cert_list;
+ gnutls_private_key *apr_pkey;
+ int apr_cert_list_length, size;
+ gnutls_datum signature;
+
+ cred = _gnutls_get_cred(state->gnutls_key, GNUTLS_X509PKI, NULL);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFICIENT_CRED;
+ }
+ if (cred->ncerts == 0) {
+ apr_cert_list = NULL;
+ apr_cert_list_length = 0;
+ apr_pkey = NULL;
+ } else {
+ ind = state->gnutls_internals.client_certificate_index;
+ if (ind < 0) {
+ apr_cert_list = NULL;
+ apr_cert_list_length = 0;
+ apr_pkey = NULL;
+ } else {
+ apr_cert_list = cred->cert_list[ind];
+ apr_cert_list_length = cred->cert_list_length[ind];
+ apr_pkey = &cred->pkey[ind];
+ }
+ }
+
+ if (apr_pkey != NULL) {
+ if ( (ret=_gnutls_generate_sig( state, apr_pkey, &signature)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ } else {
+ gnutls_assert();
+ return 0;
+ }
+
+ *data = gnutls_malloc(signature.size+2);
+ if (*data==NULL) {
+ gnutls_free_datum( &signature);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ size = signature.size;
+ WRITEuint16( size, *data);
+
+ memcpy( &(*data)[2], signature.data, size);
+
+ gnutls_free_datum( &signature);
+ return size+2;
+}
--- /dev/null
+/*
+ * 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 <x509_b64.h>
+#include <auth_x509.h>
+#include <gnutls_cert.h>
+#include <x509_asn1.h>
+#include <x509_der.h>
+#include <gnutls_datum.h>
+#include <gnutls_gcry.h>
+#include <gnutls_privkey.h>
+#include <gnutls_global.h>
+#include <gnutls_pk.h>
+#include <debug.h>
+#include <gnutls_buffers.h>
+#include <gnutls_sig.h>
+
+int _gnutls_generate_sig( GNUTLS_STATE state, gnutls_private_key *pkey, gnutls_datum *signature) {
+opaque digest[20+16];
+gnutls_datum data;
+GNUTLS_HASH_HANDLE td;
+int size = gnutls_getHashDataBufferSize( state);
+int ret;
+
+ data.data = gnutls_malloc(size);
+ data.size = size;
+ if (data.data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ gnutls_readHashDataFromBuffer( state, data.data, data.size);
+
+ switch(pkey->pk_algorithm) {
+ case GNUTLS_PK_RSA:
+
+ td = gnutls_hash_init( GNUTLS_MAC_MD5);
+ if (td==NULL) {
+ gnutls_assert();
+ gnutls_free_datum( &data);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ gnutls_hash( td, data.data, data.size);
+ gnutls_hash_deinit( td, digest);
+
+ td = gnutls_hash_init( GNUTLS_MAC_SHA);
+ if (td==NULL) {
+ gnutls_assert();
+ gnutls_free_datum( &data);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ gnutls_hash( td, data.data, data.size);
+ gnutls_hash_deinit( td, &digest[16]);
+ gnutls_free_datum( &data);
+
+ data.data = digest;
+ data.size = 20+16; /* md5 + sha */
+ ret = _gnutls_pkcs1_rsa_generate_sig( GNUTLS_MAC_MD5, pkey, &data, signature);
+ break;
+ default:
+ gnutls_free_datum( &data);
+ ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ break;
+ }
+
+ return ret;
+
+}
+
+static int _gnutls_digestinfo_encode( opaque* data, int data_size, char* OID, gnutls_datum* der) {
+node_asn *di;
+int result;
+
+ if (asn1_create_structure( _gnutls_get_pkcs(),
+ "PKCS-1.DigestInfo", &di, "di") != ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ result = asn1_write_value( di, "di.digestAlgorithm.algorithm", OID, 1);
+ if (result!=ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ result = asn1_write_value( di, "di.digestAlgorithm.parameters", NULL, 0);
+ if (result!=ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ result = asn1_write_value( di, "di.digest", data, data_size);
+ if (result!=ASN_OK) {
+ gnutls_assert();
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ der->size = data_size + 200;
+ der->data = gnutls_malloc( der->size);
+ if (der->data==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ result = asn1_create_der( di, "di", der->data, &der->size);
+ if (result!=ASN_OK) {
+ gnutls_assert();
+ gnutls_free_datum( der);
+ return GNUTLS_E_ASN1_ERROR;
+ }
+
+ return 0;
+}
+
+int _gnutls_pkcs1_rsa_generate_sig( MACAlgorithm hash_algo, gnutls_private_key *pkey, const gnutls_datum *data, gnutls_datum *signature) {
+ GNUTLS_HASH_HANDLE hd;
+ opaque digest[MAX_HASH_SIZE];
+ int digest_size = gnutls_hash_get_algo_len( hash_algo), ret;
+ char OID[40];
+ gnutls_datum der;
+
+ if (hash_algo==GNUTLS_MAC_MD5)
+ strcpy(OID, "1 2 840 113549 2 5");
+ else if (hash_algo==GNUTLS_MAC_SHA)
+ strcpy(OID, "1 3 14 3 2 26");
+ else {
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
+ }
+
+ /* hash data */
+ hd = gnutls_hash_init( hash_algo);
+ if (hd==NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ gnutls_hash( hd, data->data, data->size);
+ gnutls_hash_deinit( hd, digest);
+
+
+ /* encode digest to DigestInfo (der) */
+ if ( (ret=_gnutls_digestinfo_encode( digest, digest_size, OID, &der)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* encrypt der */
+ if ( (ret=_gnutls_pkcs1_rsa_encrypt( signature, der, pkey->params[0], pkey->params[1], 1)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ gnutls_free_datum( &der);
+ return 0;
+}