mirror of https://github.com/ipxe/ipxe.git
[crypto] Allow private key to be specified as a TLS connection parameter
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/182/head
parent
6a8664d9ec
commit
f43a8f8b9f
|
@ -116,13 +116,13 @@ struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) {
|
|||
* @v key Private key
|
||||
* @ret cert X.509 certificate, or NULL if not found
|
||||
*/
|
||||
struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) {
|
||||
struct x509_certificate * certstore_find_key ( struct private_key *key ) {
|
||||
struct x509_certificate *cert;
|
||||
|
||||
/* Search for certificate within store */
|
||||
list_for_each_entry ( cert, &certstore.links, store.list ) {
|
||||
if ( pubkey_match ( cert->signature_algorithm->pubkey,
|
||||
key->data, key->len,
|
||||
key->builder.data, key->builder.len,
|
||||
cert->subject.public_key.raw.data,
|
||||
cert->subject.public_key.raw.len ) == 0 )
|
||||
return certstore_found ( cert );
|
||||
|
|
|
@ -64,9 +64,12 @@ __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t"
|
|||
".previous\n\t" );
|
||||
|
||||
/** Private key */
|
||||
struct asn1_cursor private_key = {
|
||||
.data = private_key_data,
|
||||
.len = ( ( size_t ) private_key_len ),
|
||||
struct private_key private_key = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.builder = {
|
||||
.data = private_key_data,
|
||||
.len = ( ( size_t ) private_key_len ),
|
||||
},
|
||||
};
|
||||
|
||||
/** Default private key */
|
||||
|
@ -83,6 +86,19 @@ static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = {
|
|||
.type = &setting_type_hex,
|
||||
};
|
||||
|
||||
/**
|
||||
* Free private key
|
||||
*
|
||||
* @v refcnt Reference counter
|
||||
*/
|
||||
void privkey_free ( struct refcnt *refcnt ) {
|
||||
struct private_key *key =
|
||||
container_of ( refcnt, struct private_key, refcnt );
|
||||
|
||||
free ( key->builder.data );
|
||||
free ( key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply private key configuration settings
|
||||
*
|
||||
|
@ -98,23 +114,24 @@ static int privkey_apply_settings ( void ) {
|
|||
if ( ALLOW_KEY_OVERRIDE ) {
|
||||
|
||||
/* Restore default private key */
|
||||
memcpy ( &private_key, &default_private_key,
|
||||
sizeof ( private_key ) );
|
||||
memcpy ( &private_key.builder, &default_private_key,
|
||||
sizeof ( private_key.builder ) );
|
||||
|
||||
/* Fetch new private key, if any */
|
||||
free ( key_data );
|
||||
if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting,
|
||||
&key_data ) ) >= 0 ) {
|
||||
private_key.data = key_data;
|
||||
private_key.len = len;
|
||||
private_key.builder.data = key_data;
|
||||
private_key.builder.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Debug */
|
||||
if ( private_key.len ) {
|
||||
if ( private_key.builder.len ) {
|
||||
DBGC ( &private_key, "PRIVKEY using %s private key:\n",
|
||||
( key_data ? "external" : "built-in" ) );
|
||||
DBGC_HDA ( &private_key, 0, private_key.data, private_key.len );
|
||||
DBGC_HDA ( &private_key, 0, private_key.builder.data,
|
||||
private_key.builder.len );
|
||||
} else {
|
||||
DBGC ( &private_key, "PRIVKEY has no private key\n" );
|
||||
}
|
||||
|
|
|
@ -11,11 +11,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/privkey.h>
|
||||
|
||||
extern struct x509_chain certstore;
|
||||
|
||||
extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw );
|
||||
extern struct x509_certificate * certstore_find_key ( struct asn1_cursor *key );
|
||||
extern struct x509_certificate * certstore_find_key ( struct private_key *key );
|
||||
extern void certstore_add ( struct x509_certificate *cert );
|
||||
extern void certstore_del ( struct x509_certificate *cert );
|
||||
|
||||
|
|
|
@ -10,7 +10,60 @@
|
|||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/refcnt.h>
|
||||
|
||||
extern struct asn1_cursor private_key;
|
||||
/** A private key */
|
||||
struct private_key {
|
||||
/** Reference counter */
|
||||
struct refcnt refcnt;
|
||||
/** ASN.1 object builder */
|
||||
struct asn1_builder builder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get reference to private key
|
||||
*
|
||||
* @v key Private key
|
||||
* @ret key Private key
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) struct private_key *
|
||||
privkey_get ( struct private_key *key ) {
|
||||
ref_get ( &key->refcnt );
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop reference to private key
|
||||
*
|
||||
* @v key Private key
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
privkey_put ( struct private_key *key ) {
|
||||
ref_put ( &key->refcnt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get private key ASN.1 cursor
|
||||
*
|
||||
* @v key Private key
|
||||
* @ret cursor ASN.1 cursor
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) struct asn1_cursor *
|
||||
privkey_cursor ( struct private_key *key ) {
|
||||
return asn1_built ( &key->builder );
|
||||
}
|
||||
|
||||
extern void privkey_free ( struct refcnt *refcnt );
|
||||
|
||||
/**
|
||||
* Initialise empty private key
|
||||
*
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
privkey_init ( struct private_key *key ) {
|
||||
ref_init ( &key->refcnt, privkey_free );
|
||||
}
|
||||
|
||||
extern struct private_key private_key;
|
||||
|
||||
#endif /* _IPXE_PRIVKEY_H */
|
||||
|
|
|
@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/sha256.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/privkey.h>
|
||||
#include <ipxe/pending.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/tables.h>
|
||||
|
@ -257,6 +258,8 @@ struct tls_session {
|
|||
const char *name;
|
||||
/** Root of trust */
|
||||
struct x509_root *root;
|
||||
/** Private key */
|
||||
struct private_key *key;
|
||||
|
||||
/** Session ID */
|
||||
uint8_t id[32];
|
||||
|
@ -322,6 +325,8 @@ struct tls_connection {
|
|||
struct digest_algorithm *handshake_digest;
|
||||
/** Digest algorithm context used for handshake verification */
|
||||
uint8_t *handshake_ctx;
|
||||
/** Private key */
|
||||
struct private_key *key;
|
||||
/** Client certificate chain (if used) */
|
||||
struct x509_chain *certs;
|
||||
/** Secure renegotiation flag */
|
||||
|
@ -384,6 +389,6 @@ struct tls_connection {
|
|||
#define TLS_RX_ALIGN 16
|
||||
|
||||
extern int add_tls ( struct interface *xfer, const char *name,
|
||||
struct x509_root *root );
|
||||
struct x509_root *root, struct private_key *key );
|
||||
|
||||
#endif /* _IPXE_TLS_H */
|
||||
|
|
|
@ -46,7 +46,7 @@ FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 );
|
|||
*/
|
||||
static int https_filter ( struct http_connection *conn ) {
|
||||
|
||||
return add_tls ( &conn->socket, conn->uri->host, NULL );
|
||||
return add_tls ( &conn->socket, conn->uri->host, NULL, NULL );
|
||||
}
|
||||
|
||||
/** HTTPS URI opener */
|
||||
|
|
|
@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) {
|
|||
}
|
||||
|
||||
/* Add TLS filter */
|
||||
if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) {
|
||||
if ( ( rc = add_tls ( &syslogs, server, NULL, NULL ) ) != 0 ) {
|
||||
DBG ( "SYSLOGS cannot create TLS filter: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_add_tls;
|
||||
|
|
|
@ -352,6 +352,7 @@ static void free_tls_session ( struct refcnt *refcnt ) {
|
|||
|
||||
/* Free dynamically-allocated resources */
|
||||
x509_root_put ( session->root );
|
||||
privkey_put ( session->key );
|
||||
free ( session->ticket );
|
||||
|
||||
/* Free session */
|
||||
|
@ -383,6 +384,7 @@ static void free_tls ( struct refcnt *refcnt ) {
|
|||
x509_chain_put ( tls->certs );
|
||||
x509_chain_put ( tls->chain );
|
||||
x509_root_put ( tls->root );
|
||||
privkey_put ( tls->key );
|
||||
|
||||
/* Drop reference to session */
|
||||
assert ( list_empty ( &tls->list ) );
|
||||
|
@ -1259,6 +1261,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
|
|||
struct digest_algorithm *digest = tls->handshake_digest;
|
||||
struct x509_certificate *cert = x509_first ( tls->certs );
|
||||
struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
|
||||
struct asn1_cursor *key = privkey_cursor ( tls->key );
|
||||
uint8_t digest_out[ digest->digestsize ];
|
||||
uint8_t ctx[ pubkey->ctxsize ];
|
||||
struct tls_signature_hash_algorithm *sig_hash = NULL;
|
||||
|
@ -1268,8 +1271,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
|
|||
tls_verify_handshake ( tls, digest_out );
|
||||
|
||||
/* Initialise public-key algorithm */
|
||||
if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data,
|
||||
private_key.len ) ) != 0 ) {
|
||||
if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not initialise %s client private "
|
||||
"key: %s\n", tls, pubkey->name, strerror ( rc ) );
|
||||
goto err_pubkey_init;
|
||||
|
@ -1876,7 +1878,7 @@ static int tls_new_certificate_request ( struct tls_connection *tls,
|
|||
tls->certs = NULL;
|
||||
|
||||
/* Determine client certificate to be sent */
|
||||
cert = certstore_find_key ( &private_key );
|
||||
cert = certstore_find_key ( tls->key );
|
||||
if ( ! cert ) {
|
||||
DBGC ( tls, "TLS %p could not find certificate corresponding "
|
||||
"to private key\n", tls );
|
||||
|
@ -3100,7 +3102,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
|
|||
/* Find existing matching session, if any */
|
||||
list_for_each_entry ( session, &tls_sessions, list ) {
|
||||
if ( ( strcmp ( name, session->name ) == 0 ) &&
|
||||
( tls->root == session->root ) ) {
|
||||
( tls->root == session->root ) &&
|
||||
( tls->key == session->key ) ) {
|
||||
ref_get ( &session->refcnt );
|
||||
tls->session = session;
|
||||
DBGC ( tls, "TLS %p joining session %s\n", tls, name );
|
||||
|
@ -3120,6 +3123,7 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
|
|||
strcpy ( name_copy, name );
|
||||
session->name = name_copy;
|
||||
session->root = x509_root_get ( tls->root );
|
||||
session->key = privkey_get ( tls->key );
|
||||
INIT_LIST_HEAD ( &session->conn );
|
||||
list_add ( &session->list, &tls_sessions );
|
||||
|
||||
|
@ -3147,10 +3151,11 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
|
|||
* @v xfer Data transfer interface
|
||||
* @v name Host name
|
||||
* @v root Root of trust (or NULL to use default)
|
||||
* @v key Private key (or NULL to use default)
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int add_tls ( struct interface *xfer, const char *name,
|
||||
struct x509_root *root ) {
|
||||
struct x509_root *root, struct private_key *key ) {
|
||||
struct tls_connection *tls;
|
||||
int rc;
|
||||
|
||||
|
@ -3168,6 +3173,7 @@ int add_tls ( struct interface *xfer, const char *name,
|
|||
intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
|
||||
process_init_stopped ( &tls->process, &tls_process_desc,
|
||||
&tls->refcnt );
|
||||
tls->key = privkey_get ( key ? key : &private_key );
|
||||
tls->root = x509_root_get ( root ? root : &root_certificates );
|
||||
tls->version = TLS_VERSION_TLS_1_2;
|
||||
tls_clear_cipher ( tls, &tls->tx_cipherspec );
|
||||
|
|
Loading…
Reference in New Issue