mirror of
https://github.com/ipxe/ipxe
synced 2025-12-27 01:52:39 +03:00
[crypto] Generalise X.509 cache to a full certificate store
Expand the concept of the X.509 cache to provide the functionality of a certificate store. Certificates in the store will be automatically used to complete certificate chains where applicable. The certificate store may be prepopulated at build time using the CERT=... build command line option. For example: make bin/ipxe.usb CERT=mycert1.crt,mycert2.crt Certificates within the certificate store are not implicitly trusted; the trust list is specified using TRUST=... as before. For example: make bin/ipxe.usb CERT=root.crt TRUST=root.crt This can be used to embed the full trusted root certificate within the iPXE binary, which is potentially useful in an HTTPS-only environment in which there is no HTTP server from which to automatically download cross-signed certificates or other certificate chain fragments. This usage of CERT= extends the existing use of CERT= to specify the client certificate. The client certificate is now identified automatically by checking for a match against the private key. For example: make bin/ipxe.usb CERT=root.crt,client.crt TRUST=root.crt KEY=client.key Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -43,7 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/open.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/clientcert.h>
|
||||
#include <ipxe/privkey.h>
|
||||
#include <ipxe/certstore.h>
|
||||
#include <ipxe/rbg.h>
|
||||
#include <ipxe/validator.h>
|
||||
#include <ipxe/tls.h>
|
||||
@@ -157,6 +158,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define EINFO_EPERM_VERIFY \
|
||||
__einfo_uniqify ( EINFO_EPERM, 0x02, \
|
||||
"Handshake verification failed" )
|
||||
#define EPERM_CLIENT_CERT __einfo_error ( EINFO_EPERM_CLIENT_CERT )
|
||||
#define EINFO_EPERM_CLIENT_CERT \
|
||||
__einfo_uniqify ( EINFO_EPERM, 0x03, \
|
||||
"No suitable client certificate available" )
|
||||
#define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
|
||||
#define EINFO_EPROTO_VERSION \
|
||||
__einfo_uniqify ( EINFO_EPROTO, 0x01, \
|
||||
@@ -307,6 +312,7 @@ static void free_tls ( struct refcnt *refcnt ) {
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
x509_put ( tls->cert );
|
||||
x509_chain_put ( tls->chain );
|
||||
|
||||
/* Free TLS structure itself */
|
||||
@@ -1030,41 +1036,16 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_send_certificate ( struct tls_session *tls ) {
|
||||
int num_certificates = ( have_client_certificate() ? 1 : 0 );
|
||||
struct {
|
||||
uint32_t type_length;
|
||||
uint8_t length[3];
|
||||
struct {
|
||||
uint8_t length[3];
|
||||
uint8_t data[ client_certificate.len ];
|
||||
} __attribute__ (( packed )) certificates[num_certificates];
|
||||
uint8_t data[ tls->cert->raw.len ];
|
||||
} __attribute__ (( packed )) certificates[1];
|
||||
} __attribute__ (( packed )) *certificate;
|
||||
struct x509_certificate *cert;
|
||||
int rc;
|
||||
|
||||
/* If we have a certificate to send, determine the applicable
|
||||
* public-key algorithm and schedule transmission of
|
||||
* CertificateVerify.
|
||||
*/
|
||||
if ( num_certificates ) {
|
||||
|
||||
/* Parse certificate to determine public-key algorithm */
|
||||
if ( ( rc = x509_certificate ( client_certificate.data,
|
||||
client_certificate.len,
|
||||
&cert ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not parse client "
|
||||
"certificate: %s\n", tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
tls->verify_pubkey = cert->signature_algorithm->pubkey;
|
||||
x509_put ( cert );
|
||||
cert = NULL;
|
||||
|
||||
/* Schedule CertificateVerify transmission */
|
||||
tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
|
||||
tls_tx_resume ( tls );
|
||||
}
|
||||
|
||||
/* Allocate storage for Certificate record (which may be too
|
||||
* large for the stack).
|
||||
*/
|
||||
@@ -1079,13 +1060,11 @@ static int tls_send_certificate ( struct tls_session *tls ) {
|
||||
sizeof ( certificate->type_length ) ) );
|
||||
tls_set_uint24 ( certificate->length,
|
||||
sizeof ( certificate->certificates ) );
|
||||
if ( num_certificates ) {
|
||||
tls_set_uint24 ( certificate->certificates[0].length,
|
||||
sizeof ( certificate->certificates[0].data ) );
|
||||
memcpy ( certificate->certificates[0].data,
|
||||
client_certificate.data,
|
||||
tls_set_uint24 ( certificate->certificates[0].length,
|
||||
sizeof ( certificate->certificates[0].data ) );
|
||||
}
|
||||
memcpy ( certificate->certificates[0].data,
|
||||
tls->cert->raw.data,
|
||||
sizeof ( certificate->certificates[0].data ) );
|
||||
|
||||
/* Transmit record */
|
||||
rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
|
||||
@@ -1148,7 +1127,8 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
|
||||
*/
|
||||
static int tls_send_certificate_verify ( struct tls_session *tls ) {
|
||||
struct digest_algorithm *digest = tls->handshake_digest;
|
||||
struct pubkey_algorithm *pubkey = tls->verify_pubkey;
|
||||
struct x509_certificate *cert = tls->cert;
|
||||
struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
|
||||
uint8_t digest_out[ digest->digestsize ];
|
||||
uint8_t ctx[ pubkey->ctxsize ];
|
||||
struct tls_signature_hash_algorithm *sig_hash = NULL;
|
||||
@@ -1158,8 +1138,8 @@ static int tls_send_certificate_verify ( struct tls_session *tls ) {
|
||||
tls_verify_handshake ( tls, digest_out );
|
||||
|
||||
/* Initialise public-key algorithm */
|
||||
if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data,
|
||||
client_private_key.len ) ) != 0 ) {
|
||||
if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data,
|
||||
private_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;
|
||||
@@ -1541,9 +1521,19 @@ static int tls_new_certificate_request ( struct tls_session *tls,
|
||||
* in parsing the Certificate Request.
|
||||
*/
|
||||
|
||||
/* Schedule Certificate transmission */
|
||||
tls->tx_pending |= TLS_TX_CERTIFICATE;
|
||||
tls_tx_resume ( tls );
|
||||
/* Free any existing client certificate */
|
||||
x509_put ( tls->cert );
|
||||
|
||||
/* Determine client certificate to be sent */
|
||||
tls->cert = certstore_find_key ( &private_key );
|
||||
if ( ! tls->cert ) {
|
||||
DBGC ( tls, "TLS %p could not find certificate corresponding "
|
||||
"to private key\n", tls );
|
||||
return -EPERM_CLIENT_CERT;
|
||||
}
|
||||
x509_get ( tls->cert );
|
||||
DBGC ( tls, "TLS %p sending client certificate %s\n",
|
||||
tls, x509_name ( tls->cert ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2469,6 +2459,10 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) {
|
||||
tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
|
||||
TLS_TX_CHANGE_CIPHER |
|
||||
TLS_TX_FINISHED );
|
||||
if ( tls->cert ) {
|
||||
tls->tx_pending |= ( TLS_TX_CERTIFICATE |
|
||||
TLS_TX_CERTIFICATE_VERIFY );
|
||||
}
|
||||
tls_tx_resume ( tls );
|
||||
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user