Add server-side support for ECDSA client auth
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index bfbf2cb..53b6031 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1676,7 +1676,8 @@
{
int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
- size_t n = 0, dn_size, total_dn_size;
+ size_t dn_size, total_dn_size; /* excluding length bytes */
+ size_t ct_len, sa_len; /* including length bytes */
unsigned char *buf, *p;
const x509_cert *crt;
@@ -1708,37 +1709,73 @@
p = buf + 4;
/*
- * At the moment, only RSA certificates are supported
+ * Supported certificate types
+ *
+ * ClientCertificateType certificate_types<1..2^8-1>;
+ * enum { (255) } ClientCertificateType;
*/
- *p++ = 1;
- *p++ = SSL_CERT_TYPE_RSA_SIGN;
+ ct_len = 0;
+
+#if defined(POLARSSL_RSA_C)
+ p[1 + ct_len++] = SSL_CERT_TYPE_RSA_SIGN;
+#endif
+#if defined(POLARSSL_ECDSA_C)
+ p[1 + ct_len++] = SSL_CERT_TYPE_ECDSA_SIGN;
+#endif
+
+ p[0] = ct_len++;
+ p += ct_len;
/*
* Add signature_algorithms for verify (TLS 1.2)
- * Only add current running algorithm that is already required for
- * requested ciphersuite.
*
- * Length is always 2
+ * SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>;
+ *
+ * struct {
+ * HashAlgorithm hash;
+ * SignatureAlgorithm signature;
+ * } SignatureAndHashAlgorithm;
+ *
+ * enum { (255) } HashAlgorithm;
+ * enum { (255) } SignatureAlgorithm;
*/
+ sa_len = 0;
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
{
+ /*
+ * Only use current running hash algorithm that is already required
+ * for requested ciphersuite.
+ */
ssl->handshake->verify_sig_alg = SSL_HASH_SHA256;
- *p++ = 0;
- *p++ = 2;
-
if( ssl->transform_negotiate->ciphersuite_info->mac ==
POLARSSL_MD_SHA384 )
{
ssl->handshake->verify_sig_alg = SSL_HASH_SHA384;
}
- *p++ = ssl->handshake->verify_sig_alg;
- *p++ = SSL_SIG_RSA;
+ /*
+ * Supported signature algorithms
+ */
+#if defined(POLARSSL_RSA_C)
+ p[2 + sa_len++] = ssl->handshake->verify_sig_alg;
+ p[2 + sa_len++] = SSL_SIG_RSA;
+#endif
+#if defined(POLARSSL_ECDSA_C)
+ p[2 + sa_len++] = ssl->handshake->verify_sig_alg;
+ p[2 + sa_len++] = SSL_SIG_ECDSA;
+#endif
- n += 4;
+ p[0] = (unsigned char)( sa_len >> 8 );
+ p[1] = (unsigned char)( sa_len );
+ sa_len += 2;
+ p += sa_len;
}
+ /*
+ * DistinguishedName certificate_authorities<0..2^16-1>;
+ * opaque DistinguishedName<1..2^16-1>;
+ */
p += 2;
crt = ssl->ca_chain;
@@ -1763,8 +1800,8 @@
ssl->out_msglen = p - buf;
ssl->out_msgtype = SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = SSL_HS_CERTIFICATE_REQUEST;
- ssl->out_msg[6 + n] = (unsigned char)( total_dn_size >> 8 );
- ssl->out_msg[7 + n] = (unsigned char)( total_dn_size );
+ ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 );
+ ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size );
ret = ssl_write_record( ssl );
@@ -2468,10 +2505,12 @@
static int ssl_parse_certificate_verify( ssl_context *ssl )
{
int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE;
- size_t n = 0, n1, n2;
+ size_t sa_len, sig_len;
unsigned char hash[48];
- md_type_t md_alg = POLARSSL_MD_NONE;
- unsigned int hashlen = 0;
+ size_t hashlen;
+ pk_type_t pk_alg;
+ md_type_t md_alg;
+ const md_info_t *md_info;
const ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info;
SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
@@ -2513,16 +2552,33 @@
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
}
- if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
+ /*
+ * 0 . 0 handshake type
+ * 1 . 3 handshake length
+ * 4 . 5 sig alg (TLS 1.2 only)
+ * 4+n . 5+n signature length (n = sa_len)
+ * 6+n . 6+n+m signature (m = sig_len)
+ */
+
+ if( ssl->minor_ver != SSL_MINOR_VERSION_3 )
{
+ sa_len = 0;
+
+ md_alg = POLARSSL_MD_NONE;
+ hashlen = 36;
+ }
+ else
+ {
+ sa_len = 2;
+
/*
- * As server we know we either have SSL_HASH_SHA384 or
+ * Hash: as server we know we either have SSL_HASH_SHA384 or
* SSL_HASH_SHA256
*/
- if( ssl->in_msg[4] != ssl->handshake->verify_sig_alg ||
- ssl->in_msg[5] != SSL_SIG_RSA )
+ if( ssl->in_msg[4] != ssl->handshake->verify_sig_alg )
{
- SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg for verify message" ) );
+ SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
+ " for verify message" ) );
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
}
@@ -2531,36 +2587,65 @@
else
md_alg = POLARSSL_MD_SHA256;
- n += 2;
- }
- else
- {
- hashlen = 36;
- md_alg = POLARSSL_MD_NONE;
+ /*
+ * Get hashlen from MD
+ */
+ if( ( md_info = md_info_from_type( md_alg ) ) == NULL )
+ {
+ SSL_DEBUG_MSG( 1, ( "requested hash not available " ) );
+ return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
+ }
+ hashlen = md_info->size;
+
+ /*
+ * Signature
+ */
+ switch( ssl->in_msg[5] )
+ {
+#if defined(POLARSSL_RSA_C)
+ case SSL_SIG_RSA:
+ pk_alg = POLARSSL_PK_RSA;
+ break;
+#endif
+
+#if defined(POLARSSL_ECDSA_C)
+ case SSL_SIG_ECDSA:
+ pk_alg = POLARSSL_PK_ECDSA;
+ break;
+#endif
+
+ default:
+ SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg"
+ " for verify message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+ }
+
+
+ /*
+ * Check the certificate's key type matches the signature alg
+ */
+ if( ! pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
+ {
+ SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
+ }
+
}
- /* EC NOT IMPLEMENTED YET */
- if( ! pk_can_do( &ssl->session_negotiate->peer_cert->pk,
- POLARSSL_PK_RSA ) )
- {
- return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE );
- }
+ sig_len = ( ssl->in_msg[4 + sa_len] << 8 ) | ssl->in_msg[5 + sa_len];
- n1 = pk_get_size( &ssl->session_negotiate->peer_cert->pk ) / 8;
- n2 = ( ssl->in_msg[4 + n] << 8 ) | ssl->in_msg[5 + n];
-
- if( n + n1 + 6 != ssl->in_hslen || n1 != n2 )
+ if( sa_len + sig_len + 6 != ssl->in_hslen )
{
SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
}
- ret = rsa_pkcs1_verify( pk_rsa( ssl->session_negotiate->peer_cert->pk ),
- RSA_PUBLIC, md_alg, hashlen, hash,
- ssl->in_msg + 6 + n );
+ ret = pk_verify( &ssl->session_negotiate->peer_cert->pk,
+ md_alg, hash, hashlen,
+ ssl->in_msg + 6 + sa_len, sig_len );
if( ret != 0 )
{
- SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret );
+ SSL_DEBUG_RET( 1, "pk_verify", ret );
return( ret );
}