return TRUE;
}
-METHOD(tls_crypto_t, sign_handshake, bool,
- private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer)
+/**
+ * Get the signature scheme from a TLS 1.2 hash/sig algorithm pair
+ */
+static signature_scheme_t hashsig_to_scheme(key_type_t type,
+ tls_hash_algorithm_t hash, tls_signature_algorithm_t sig)
{
- chunk_t sig, hash;
+ switch (sig)
+ {
+ case TLS_SIG_RSA:
+ if (type != KEY_RSA)
+ {
+ return SIGN_UNKNOWN;
+ }
+ switch (hash)
+ {
+ case TLS_HASH_MD5:
+ return SIGN_RSA_EMSA_PKCS1_MD5;
+ case TLS_HASH_SHA1:
+ return SIGN_RSA_EMSA_PKCS1_SHA1;
+ case TLS_HASH_SHA224:
+ return SIGN_RSA_EMSA_PKCS1_SHA224;
+ case TLS_HASH_SHA256:
+ return SIGN_RSA_EMSA_PKCS1_SHA256;
+ case TLS_HASH_SHA384:
+ return SIGN_RSA_EMSA_PKCS1_SHA384;
+ case TLS_HASH_SHA512:
+ return SIGN_RSA_EMSA_PKCS1_SHA512;
+ default:
+ return SIGN_UNKNOWN;
+ }
+ case TLS_SIG_ECDSA:
+ if (type != KEY_ECDSA)
+ {
+ return SIGN_UNKNOWN;
+ }
+ switch (hash)
+ {
+ case TLS_HASH_SHA224:
+ return SIGN_ECDSA_WITH_SHA1_DER;
+ case TLS_HASH_SHA256:
+ return SIGN_ECDSA_WITH_SHA256_DER;
+ case TLS_HASH_SHA384:
+ return SIGN_ECDSA_WITH_SHA384_DER;
+ case TLS_HASH_SHA512:
+ return SIGN_ECDSA_WITH_SHA512_DER;
+ default:
+ return SIGN_UNKNOWN;
+ }
+ default:
+ return SIGN_UNKNOWN;
+ }
+}
+METHOD(tls_crypto_t, sign_handshake, bool,
+ private_tls_crypto_t *this, private_key_t *key, tls_writer_t *writer,
+ chunk_t hashsig)
+{
if (this->tls->get_version(this->tls) >= TLS_1_2)
{
- /* TODO: use supported algorithms instead of fixed SHA1/RSA */
- if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, &sig))
+ signature_scheme_t scheme;
+ tls_reader_t *reader;
+ u_int8_t hash, alg;
+ chunk_t sig;
+ bool done = FALSE;
+
+ reader = tls_reader_create(hashsig);
+ while (reader->remaining(reader) >= 2)
{
+ if (reader->read_uint8(reader, &hash) &&
+ reader->read_uint8(reader, &alg))
+ {
+ scheme = hashsig_to_scheme(key->get_type(key), hash, alg);
+ if (scheme != SIGN_UNKNOWN &&
+ key->sign(key, scheme, this->handshake, &sig))
+ {
+ done = TRUE;
+ break;
+ }
+ }
+ }
+ reader->destroy(reader);
+ if (!done)
+ {
+ DBG1(DBG_TLS, "none of the proposed hash/sig algorithms supported");
return FALSE;
}
- writer->write_uint8(writer, 2);
- writer->write_uint8(writer, 1);
+ DBG2(DBG_TLS, "signed handshake data with %N/%N",
+ tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg);
+ writer->write_uint8(writer, hash);
+ writer->write_uint8(writer, alg);
writer->write_data16(writer, sig);
free(sig.ptr);
}
else
{
- if (!hash_handshake(this, &hash))
- {
- return FALSE;
- }
- if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
+ chunk_t sig, hash;
+
+ switch (key->get_type(key))
{
- free(hash.ptr);
- return FALSE;
+ case KEY_RSA:
+ if (!hash_handshake(this, &hash))
+ {
+ return FALSE;
+ }
+ if (!key->sign(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
+ {
+ free(hash.ptr);
+ return FALSE;
+ }
+ DBG2(DBG_TLS, "signed handshake data with SHA1+MD5/RSA");
+ free(hash.ptr);
+ break;
+ case KEY_ECDSA:
+ if (!key->sign(key, SIGN_ECDSA_WITH_SHA1_DER,
+ this->handshake, &sig))
+ {
+ return FALSE;
+ }
+ DBG2(DBG_TLS, "signed handshake data with SHA1/ECDSA");
+ break;
+ default:
+ return FALSE;
}
writer->write_data16(writer, sig);
- free(hash.ptr);
free(sig.ptr);
}
return TRUE;
{
if (this->tls->get_version(this->tls) >= TLS_1_2)
{
+ signature_scheme_t scheme = SIGN_UNKNOWN;
u_int8_t hash, alg;
chunk_t sig;
DBG1(DBG_TLS, "received invalid Certificate Verify");
return FALSE;
}
- /* TODO: map received hash/sig alg to signature scheme */
- if (hash != 2 || alg != 1 ||
- !key->verify(key, SIGN_RSA_EMSA_PKCS1_SHA1, this->handshake, sig))
+ scheme = hashsig_to_scheme(key->get_type(key), hash, alg);
+ if (scheme == SIGN_UNKNOWN)
{
+ DBG1(DBG_TLS, "Certificate Verify algorithms %N/%N not supported",
+ tls_hash_algorithm_names, hash,
+ tls_signature_algorithm_names, alg);
return FALSE;
}
+ if (!key->verify(key, scheme, this->handshake, sig))
+ {
+ return FALSE;
+ }
+ DBG2(DBG_TLS, "verified handshake data with %N/%N",
+ tls_hash_algorithm_names, hash, tls_signature_algorithm_names, alg);
}
else
{
DBG1(DBG_TLS, "received invalid Certificate Verify");
return FALSE;
}
- if (!hash_handshake(this, &hash))
- {
- return FALSE;
- }
- if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig))
+ switch (key->get_type(key))
{
- free(hash.ptr);
- return FALSE;
+ case KEY_RSA:
+ if (!hash_handshake(this, &hash))
+ {
+ return FALSE;
+ }
+ if (!key->verify(key, SIGN_RSA_EMSA_PKCS1_NULL, hash, sig))
+ {
+ free(hash.ptr);
+ return FALSE;
+ }
+ DBG2(DBG_TLS, "verified handshake data with SHA1+MD5/RSA");
+ free(hash.ptr);
+ break;
+ case KEY_ECDSA:
+ if (!key->verify(key, SIGN_ECDSA_WITH_SHA1_DER,
+ this->handshake, sig))
+ {
+ free(hash.ptr);
+ return FALSE;
+ }
+ DBG2(DBG_TLS, "verified handshake data with SHA1/ECDSA");
+ break;
+ default:
+ return FALSE;
}
- free(hash.ptr);
}
return TRUE;
}
* Peer private key
*/
private_key_t *private;
+
+ /**
+ * List of server-supported hashsig algorithms
+ */
+ chunk_t hashsig;
+
+ /**
+ * List of server-supported client certificate types
+ */
+ chunk_t cert_types;
};
/**
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
+ this->cert_types = chunk_clone(types);
if (this->tls->get_version(this->tls) >= TLS_1_2)
{
if (!reader->read_data16(reader, &hashsig))
this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR);
return NEED_MORE;
}
- /* TODO: store supported hashsig algorithms */
+ this->hashsig = chunk_clone(hashsig);
}
if (!reader->read_data16(reader, &data))
{
return NEED_MORE;
}
+/**
+ * Find a private key suitable to sign Certificate Verify
+ */
+static private_key_t *find_private_key(private_tls_peer_t *this)
+{
+ private_key_t *key = NULL;
+ tls_reader_t *reader;
+ key_type_t type;
+ u_int8_t cert;
+
+ if (!this->peer)
+ {
+ return NULL;
+ }
+ reader = tls_reader_create(this->cert_types);
+ while (reader->remaining(reader) && reader->read_uint8(reader, &cert))
+ {
+ switch (cert)
+ {
+ case TLS_RSA_SIGN:
+ type = KEY_RSA;
+ break;
+ case TLS_ECDSA_SIGN:
+ type = KEY_ECDSA;
+ break;
+ default:
+ continue;
+ }
+ key = lib->credmgr->get_private(lib->credmgr, type,
+ this->peer, this->peer_auth);
+ if (key)
+ {
+ break;
+ }
+ }
+ reader->destroy(reader);
+ return key;
+}
+
/**
* Send Certificate
*/
tls_writer_t *certs;
chunk_t data;
- if (this->peer)
- {
- this->private = lib->credmgr->get_private(lib->credmgr,
- KEY_ANY, this->peer, this->peer_auth);
- }
+ this->private = find_private_key(this);
if (!this->private)
{
DBG1(DBG_TLS, "no TLS peer certificate found for '%Y'", this->peer);
tls_handshake_type_t *type, tls_writer_t *writer)
{
if (!this->private ||
- !this->crypto->sign_handshake(this->crypto, this->private, writer))
+ !this->crypto->sign_handshake(this->crypto, this->private,
+ writer, this->hashsig))
{
DBG1(DBG_TLS, "creating TLS Certificate Verify signature failed");
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
DESTROY_IF(this->private);
this->peer_auth->destroy(this->peer_auth);
this->server_auth->destroy(this->server_auth);
+ free(this->hashsig.ptr);
+ free(this->cert_types.ptr);
free(this);
}
return NEED_MORE;
}
+/**
+ * Create a list of supported certificate types and hash/sig algorithms
+ */
+static void get_supported_algorithms(private_tls_server_t *this,
+ tls_writer_t *writer)
+{
+ tls_writer_t *supported;
+
+ supported = tls_writer_create(4);
+ /* we propose both RSA and ECDSA */
+ supported->write_uint8(supported, TLS_RSA_SIGN);
+ supported->write_uint8(supported, TLS_ECDSA_SIGN);
+ writer->write_data8(writer, supported->get_buf(supported));
+ supported->destroy(supported);
+
+ if (this->tls->get_version(this->tls) >= TLS_1_2)
+ {
+ enumerator_t *enumerator;
+ hash_algorithm_t alg;
+ tls_hash_algorithm_t hash;
+
+ supported = tls_writer_create(32);
+ enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &alg))
+ {
+ switch (alg)
+ {
+ case HASH_MD5:
+ hash = TLS_HASH_MD5;
+ break;
+ case HASH_SHA1:
+ hash = TLS_HASH_SHA1;
+ break;
+ case HASH_SHA224:
+ hash = TLS_HASH_SHA224;
+ break;
+ case HASH_SHA256:
+ hash = TLS_HASH_SHA256;
+ break;
+ case HASH_SHA384:
+ hash = TLS_HASH_SHA384;
+ break;
+ case HASH_SHA512:
+ hash = TLS_HASH_SHA512;
+ break;
+ default:
+ continue;
+ }
+ supported->write_uint8(supported, hash);
+ supported->write_uint8(supported, TLS_SIG_RSA);
+ if (alg != HASH_MD5 && alg != HASH_SHA224)
+ {
+ supported->write_uint8(supported, hash);
+ supported->write_uint8(supported, TLS_SIG_ECDSA);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ writer->write_data16(writer, supported->get_buf(supported));
+ supported->destroy(supported);
+ }
+}
+
/**
* Send Certificate Request
*/
x509_t *x509;
identification_t *id;
- /* currently only RSA signatures are supported */
- writer->write_data8(writer, chunk_from_chars(1));
- if (this->tls->get_version(this->tls) >= TLS_1_2)
- {
- /* enforce RSA with SHA1 signatures */
- writer->write_data16(writer, chunk_from_chars(2, 1));
- }
+ get_supported_algorithms(this, writer);
authorities = tls_writer_create(64);
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,