mirror of https://github.com/ipxe/ipxe.git
[tls] Use iPXE native RSA algorithm
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/6/head
parent
7fb064470f
commit
dc87161c30
|
@ -33,161 +33,33 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
* documented in RFC2313.
|
||||
*/
|
||||
|
||||
/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
|
||||
static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x01 };
|
||||
|
||||
/**
|
||||
* Identify X.509 certificate public key
|
||||
* Identify X.509 certificate RSA public key
|
||||
*
|
||||
* @v certificate Certificate
|
||||
* @v algorithm Public key algorithm to fill in
|
||||
* @v pubkey Public key value to fill in
|
||||
* @v rsa RSA public key to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int x509_public_key ( const struct asn1_cursor *certificate,
|
||||
struct asn1_cursor *algorithm,
|
||||
struct asn1_cursor *pubkey ) {
|
||||
struct asn1_cursor cursor;
|
||||
int x509_rsa_public_key ( const struct asn1_cursor *certificate,
|
||||
struct x509_rsa_public_key *key ) {
|
||||
struct asn1_cursor *cursor = &key->raw;
|
||||
int rc;
|
||||
|
||||
/* Locate subjectPublicKeyInfo */
|
||||
memcpy ( &cursor, certificate, sizeof ( cursor ) );
|
||||
rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
|
||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
|
||||
asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
|
||||
memcpy ( cursor, certificate, sizeof ( *cursor ) );
|
||||
rc = ( asn1_enter ( cursor, ASN1_SEQUENCE ), /* Certificate */
|
||||
asn1_enter ( cursor, ASN1_SEQUENCE ), /* tbsCertificate */
|
||||
asn1_skip_if_exists ( cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
|
||||
asn1_skip ( cursor, ASN1_INTEGER ), /* serialNumber */
|
||||
asn1_skip ( cursor, ASN1_SEQUENCE ), /* signature */
|
||||
asn1_skip ( cursor, ASN1_SEQUENCE ), /* issuer */
|
||||
asn1_skip ( cursor, ASN1_SEQUENCE ), /* validity */
|
||||
asn1_skip ( cursor, ASN1_SEQUENCE ) /* name */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Locate algorithm */
|
||||
memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
|
||||
rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate algorithm in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Locate subjectPublicKey */
|
||||
memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
|
||||
rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
|
||||
asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate subjectPublicKey in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify X.509 certificate RSA modulus and public exponent
|
||||
*
|
||||
* @v certificate Certificate
|
||||
* @v rsa RSA public key to fill in
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The caller is responsible for eventually calling
|
||||
* x509_free_rsa_public_key() to free the storage allocated to hold
|
||||
* the RSA modulus and exponent.
|
||||
*/
|
||||
int x509_rsa_public_key ( const struct asn1_cursor *certificate,
|
||||
struct x509_rsa_public_key *rsa_pubkey ) {
|
||||
struct asn1_cursor algorithm;
|
||||
struct asn1_cursor pubkey;
|
||||
struct asn1_cursor modulus;
|
||||
struct asn1_cursor exponent;
|
||||
int rc;
|
||||
|
||||
/* First, extract the public key algorithm and key data */
|
||||
if ( ( rc = x509_public_key ( certificate, &algorithm,
|
||||
&pubkey ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Check that algorithm is RSA */
|
||||
rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate algorithm:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return rc;
|
||||
}
|
||||
if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
|
||||
( memcmp ( algorithm.data, &oid_rsa_encryption,
|
||||
sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
|
||||
DBG ( "algorithm is not rsaEncryption in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Check that public key is a byte string, i.e. that the
|
||||
* "unused bits" byte contains zero.
|
||||
*/
|
||||
if ( ( pubkey.len < 1 ) ||
|
||||
( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
|
||||
DBG ( "subjectPublicKey is not a byte string in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
pubkey.data++;
|
||||
pubkey.len--;
|
||||
|
||||
/* Pick out the modulus and exponent */
|
||||
rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate RSAPublicKey in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
|
||||
rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate modulus in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( modulus.len && ( ! *( ( uint8_t * ) modulus.data ) ) ) {
|
||||
/* Skip positive sign byte */
|
||||
modulus.data++;
|
||||
modulus.len--;
|
||||
}
|
||||
memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
|
||||
rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
|
||||
asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
|
||||
if ( rc != 0 ) {
|
||||
DBG ( "Cannot locate publicExponent in:\n" );
|
||||
DBG_HDA ( 0, certificate->data, certificate->len );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( exponent.len && ( ! *( ( uint8_t * ) exponent.data ) ) ) {
|
||||
/* Skip positive sign byte */
|
||||
exponent.data++;
|
||||
exponent.len--;
|
||||
}
|
||||
|
||||
/* Allocate space and copy out modulus and exponent */
|
||||
rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
|
||||
if ( ! rsa_pubkey->modulus )
|
||||
return -ENOMEM;
|
||||
rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
|
||||
memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
|
||||
rsa_pubkey->modulus_len = modulus.len;
|
||||
memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
|
||||
rsa_pubkey->exponent_len = exponent.len;
|
||||
|
||||
DBG2 ( "RSA modulus:\n" );
|
||||
DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
|
||||
DBG2 ( "RSA exponent:\n" );
|
||||
DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -182,9 +182,6 @@ struct tls_session {
|
|||
/** SHA256 context for handshake verification */
|
||||
uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE];
|
||||
|
||||
/** Hack: server RSA public key */
|
||||
struct x509_rsa_public_key rsa;
|
||||
|
||||
/** TX sequence number */
|
||||
uint64_t tx_seq;
|
||||
/** TX pending transmissions */
|
||||
|
|
|
@ -11,31 +11,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct asn1_cursor;
|
||||
#include <ipxe/asn1.h>
|
||||
|
||||
/** An X.509 RSA public key */
|
||||
struct x509_rsa_public_key {
|
||||
/** Modulus */
|
||||
uint8_t *modulus;
|
||||
/** Modulus length */
|
||||
size_t modulus_len;
|
||||
/** Exponent */
|
||||
uint8_t *exponent;
|
||||
/** Exponent length */
|
||||
size_t exponent_len;
|
||||
/** Raw public key */
|
||||
struct asn1_cursor raw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Free X.509 RSA public key
|
||||
*
|
||||
* @v rsa_pubkey RSA public key
|
||||
*/
|
||||
static inline void
|
||||
x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) {
|
||||
free ( rsa_pubkey->modulus );
|
||||
}
|
||||
|
||||
extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
|
||||
struct x509_rsa_public_key *rsa_pubkey );
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/open.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/rbg.h>
|
||||
#include <ipxe/tls.h>
|
||||
|
@ -90,7 +89,6 @@ static void free_tls ( struct refcnt *refcnt ) {
|
|||
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
|
||||
tls_clear_cipher ( tls, &tls->rx_cipherspec );
|
||||
tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
|
||||
x509_free_rsa_public_key ( &tls->rsa );
|
||||
free ( tls->rx_data );
|
||||
|
||||
/* Free TLS structure itself */
|
||||
|
@ -437,28 +435,28 @@ struct tls_cipher_suite tls_cipher_suites[] = {
|
|||
{
|
||||
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.pubkey = &pubkey_null, /* FIXME */
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
},
|
||||
{
|
||||
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.pubkey = &pubkey_null, /* FIXME */
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha256_algorithm,
|
||||
},
|
||||
{
|
||||
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
|
||||
.key_len = ( 256 / 8 ),
|
||||
.pubkey = &pubkey_null, /* FIXME */
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
},
|
||||
{
|
||||
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
|
||||
.key_len = ( 128 / 8 ),
|
||||
.pubkey = &pubkey_null, /* FIXME */
|
||||
.pubkey = &rsa_algorithm,
|
||||
.cipher = &aes_cbc_algorithm,
|
||||
.digest = &sha1_algorithm,
|
||||
},
|
||||
|
@ -496,6 +494,11 @@ tls_find_cipher_suite ( unsigned int cipher_suite ) {
|
|||
*/
|
||||
static void tls_clear_cipher ( struct tls_session *tls __unused,
|
||||
struct tls_cipherspec *cipherspec ) {
|
||||
|
||||
if ( cipherspec->suite ) {
|
||||
pubkey_final ( cipherspec->suite->pubkey,
|
||||
cipherspec->pubkey_ctx );
|
||||
}
|
||||
free ( cipherspec->dynamic );
|
||||
memset ( cipherspec, 0, sizeof ( cipherspec ) );
|
||||
cipherspec->suite = &tls_cipher_suite_null;
|
||||
|
@ -523,13 +526,12 @@ static int tls_set_cipher ( struct tls_session *tls,
|
|||
|
||||
/* Allocate dynamic storage */
|
||||
total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
|
||||
dynamic = malloc ( total );
|
||||
dynamic = zalloc ( total );
|
||||
if ( ! dynamic ) {
|
||||
DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
|
||||
"context\n", tls, total );
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset ( dynamic, 0, total );
|
||||
|
||||
/* Assign storage */
|
||||
cipherspec->dynamic = dynamic;
|
||||
|
@ -793,37 +795,38 @@ static int tls_send_certificate ( struct tls_session *tls ) {
|
|||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_send_client_key_exchange ( struct tls_session *tls ) {
|
||||
/* FIXME: Hack alert */
|
||||
RSA_CTX *rsa_ctx = NULL;
|
||||
RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
|
||||
tls->rsa.exponent, tls->rsa.exponent_len );
|
||||
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
|
||||
struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
|
||||
size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx );
|
||||
struct {
|
||||
uint32_t type_length;
|
||||
uint16_t encrypted_pre_master_secret_len;
|
||||
uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
|
||||
uint8_t encrypted_pre_master_secret[max_len];
|
||||
} __attribute__ (( packed )) key_xchg;
|
||||
size_t unused;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Encrypt pre-master secret using server's public key */
|
||||
memset ( &key_xchg, 0, sizeof ( key_xchg ) );
|
||||
key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
|
||||
htonl ( sizeof ( key_xchg ) -
|
||||
sizeof ( key_xchg.type_length ) ) );
|
||||
key_xchg.encrypted_pre_master_secret_len
|
||||
= htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
|
||||
|
||||
/* FIXME: Hack alert */
|
||||
DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
|
||||
DBGC_HD ( tls, &tls->pre_master_secret,
|
||||
sizeof ( tls->pre_master_secret ) );
|
||||
DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
|
||||
DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
|
||||
RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
|
||||
sizeof ( tls->pre_master_secret ),
|
||||
key_xchg.encrypted_pre_master_secret, 0 );
|
||||
DBGC ( tls, "RSA encrypt done. Ciphertext:\n" );
|
||||
DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
|
||||
sizeof ( key_xchg.encrypted_pre_master_secret ) );
|
||||
RSA_free ( rsa_ctx );
|
||||
|
||||
len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx,
|
||||
&tls->pre_master_secret,
|
||||
sizeof ( tls->pre_master_secret ),
|
||||
key_xchg.encrypted_pre_master_secret );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
unused = ( max_len - len );
|
||||
key_xchg.type_length =
|
||||
( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
|
||||
htonl ( sizeof ( key_xchg ) -
|
||||
sizeof ( key_xchg.type_length ) - unused ) );
|
||||
key_xchg.encrypted_pre_master_secret_len =
|
||||
htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) -
|
||||
unused );
|
||||
|
||||
return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
|
||||
}
|
||||
|
@ -1021,7 +1024,10 @@ static int tls_new_certificate ( struct tls_session *tls,
|
|||
( ( void * ) certificate->certificates );
|
||||
size_t elements_len = tls_uint24 ( certificate->length );
|
||||
const void *end = ( certificate->certificates + elements_len );
|
||||
struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
|
||||
struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
|
||||
struct asn1_cursor cursor;
|
||||
struct x509_rsa_public_key key;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
|
@ -1044,12 +1050,20 @@ static int tls_new_certificate ( struct tls_session *tls,
|
|||
}
|
||||
|
||||
// HACK
|
||||
if ( ( rc = x509_rsa_public_key ( &cursor,
|
||||
&tls->rsa ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p cannot determine RSA public key: "
|
||||
"%s\n", tls, strerror ( rc ) );
|
||||
if ( ( rc = x509_rsa_public_key ( &cursor, &key ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p cannot parse public key: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialise public key algorithm */
|
||||
if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
|
||||
key.raw.data, key.raw.len ) ) != 0){
|
||||
DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
element = ( cursor.data + cursor.len );
|
||||
|
|
Loading…
Reference in New Issue