Browse Source

[tls] Support sending a client certificate

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
cf78afa5c5
2 changed files with 268 additions and 15 deletions
  1. 31
    2
      src/include/ipxe/tls.h
  2. 237
    13
      src/net/tls.c

+ 31
- 2
src/include/ipxe/tls.h View File

@@ -80,6 +80,14 @@ struct tls_header {
80 80
 #define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003c
81 81
 #define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003d
82 82
 
83
+/* TLS hash algorithm identifiers */
84
+#define TLS_MD5_ALGORITHM 1
85
+#define TLS_SHA1_ALGORITHM 2
86
+#define TLS_SHA256_ALGORITHM 4
87
+
88
+/* TLS signature algorithm identifiers */
89
+#define TLS_RSA_ALGORITHM 1
90
+
83 91
 /* TLS extension types */
84 92
 #define TLS_SERVER_NAME 0
85 93
 #define TLS_SERVER_NAME_HOST_NAME 0
@@ -95,8 +103,9 @@ enum tls_tx_pending {
95 103
 	TLS_TX_CLIENT_HELLO = 0x0001,
96 104
 	TLS_TX_CERTIFICATE = 0x0002,
97 105
 	TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004,
98
-	TLS_TX_CHANGE_CIPHER = 0x0008,
99
-	TLS_TX_FINISHED = 0x0010,
106
+	TLS_TX_CERTIFICATE_VERIFY = 0x0008,
107
+	TLS_TX_CHANGE_CIPHER = 0x0010,
108
+	TLS_TX_FINISHED = 0x0020,
100 109
 };
101 110
 
102 111
 /** A TLS cipher suite */
@@ -129,6 +138,24 @@ struct tls_cipherspec {
129 138
 	void *mac_secret;
130 139
 };
131 140
 
141
+/** A TLS signature and hash algorithm identifier */
142
+struct tls_signature_hash_id {
143
+	/** Hash algorithm */
144
+	uint8_t hash;
145
+	/** Signature algorithm */
146
+	uint8_t signature;
147
+} __attribute__ (( packed ));
148
+
149
+/** A TLS signature algorithm */
150
+struct tls_signature_hash_algorithm {
151
+	/** Digest algorithm */
152
+	struct digest_algorithm *digest;
153
+	/** Public-key algorithm */
154
+	struct pubkey_algorithm *pubkey;
155
+	/** Numeric code */
156
+	struct tls_signature_hash_id code;
157
+};
158
+
132 159
 /** TLS pre-master secret */
133 160
 struct tls_pre_master_secret {
134 161
 	/** TLS version */
@@ -205,6 +232,8 @@ struct tls_session {
205 232
 	struct digest_algorithm *handshake_digest;
206 233
 	/** Digest algorithm context used for handshake verification */
207 234
 	uint8_t *handshake_ctx;
235
+	/** Public-key algorithm used for Certificate Verify (if sent) */
236
+	struct pubkey_algorithm *verify_pubkey;
208 237
 
209 238
 	/** TX sequence number */
210 239
 	uint64_t tx_seq;

+ 237
- 13
src/net/tls.c View File

@@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
41 41
 #include <ipxe/xfer.h>
42 42
 #include <ipxe/open.h>
43 43
 #include <ipxe/x509.h>
44
+#include <ipxe/clientcert.h>
44 45
 #include <ipxe/rbg.h>
45 46
 #include <ipxe/tls.h>
46 47
 
@@ -75,8 +76,25 @@ static void tls_clear_cipher ( struct tls_session *tls,
75 76
  * TLS uses 24-bit integers in several places, which are awkward to
76 77
  * parse in C.
77 78
  */
78
-static unsigned long tls_uint24 ( const uint8_t field24[3] ) {
79
-	return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
79
+static inline __attribute__ (( always_inline )) unsigned long
80
+tls_uint24 ( const uint8_t field24[3] ) {
81
+	const uint32_t *field32 __attribute__ (( may_alias )) =
82
+		( ( const void * ) field24 );
83
+	return ( be32_to_cpu ( *field32 ) >> 8 );
84
+}
85
+
86
+/**
87
+ * Set 24-bit field value
88
+ *
89
+ * @v field24		24-bit field
90
+ * @v value		Field value
91
+ *
92
+ * The field must be pre-zeroed.
93
+ */
94
+static void tls_set_uint24 ( uint8_t field24[3], unsigned long value ) {
95
+	uint32_t *field32 __attribute__ (( may_alias )) =
96
+		( ( void * ) field24 );
97
+	*field32 |= cpu_to_be32 ( value << 8 );
80 98
 }
81 99
 
82 100
 /******************************************************************************
@@ -137,6 +155,13 @@ static struct digest_algorithm md5_sha1_algorithm = {
137 155
 	.final		= md5_sha1_final,
138 156
 };
139 157
 
158
+/** RSA digestInfo prefix for MD5+SHA1 algorithm */
159
+struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = {
160
+	.digest = &md5_sha1_algorithm,
161
+	.data = NULL, /* MD5+SHA1 signatures have no digestInfo */
162
+	.len = 0,
163
+};
164
+
140 165
 /******************************************************************************
141 166
  *
142 167
  * Cleanup functions
@@ -674,6 +699,59 @@ static int tls_change_cipher ( struct tls_session *tls,
674 699
 	return 0;
675 700
 }
676 701
 
702
+/******************************************************************************
703
+ *
704
+ * Signature and hash algorithms
705
+ *
706
+ ******************************************************************************
707
+ */
708
+
709
+/** Supported signature and hash algorithms
710
+ *
711
+ * Note that the default (TLSv1.1 and earlier) algorithm using
712
+ * MD5+SHA1 is never explicitly specified.
713
+ */
714
+struct tls_signature_hash_algorithm tls_signature_hash_algorithms[] = {
715
+	{
716
+		.code = {
717
+			.signature = TLS_RSA_ALGORITHM,
718
+			.hash = TLS_SHA256_ALGORITHM,
719
+		},
720
+		.pubkey = &rsa_algorithm,
721
+		.digest = &sha256_algorithm,
722
+	},
723
+};
724
+
725
+/** Number of supported signature and hash algorithms */
726
+#define TLS_NUM_SIG_HASH_ALGORITHMS			\
727
+	( sizeof ( tls_signature_hash_algorithms ) /	\
728
+	  sizeof ( tls_signature_hash_algorithms[0] ) )
729
+
730
+/**
731
+ * Find TLS signature and hash algorithm
732
+ *
733
+ * @v pubkey		Public-key algorithm
734
+ * @v digest		Digest algorithm
735
+ * @ret sig_hash	Signature and hash algorithm, or NULL
736
+ */
737
+static struct tls_signature_hash_algorithm *
738
+tls_signature_hash_algorithm ( struct pubkey_algorithm *pubkey,
739
+			       struct digest_algorithm *digest ) {
740
+	struct tls_signature_hash_algorithm *sig_hash;
741
+	unsigned int i;
742
+
743
+	/* Identify signature and hash algorithm */
744
+	for ( i = 0 ; i < TLS_NUM_SIG_HASH_ALGORITHMS ; i++ ) {
745
+		sig_hash = &tls_signature_hash_algorithms[i];
746
+		if ( ( sig_hash->pubkey == pubkey ) &&
747
+		     ( sig_hash->digest == digest ) ) {
748
+			return sig_hash;
749
+		}
750
+	}
751
+
752
+	return NULL;
753
+}
754
+
677 755
 /******************************************************************************
678 756
  *
679 757
  * Handshake verification
@@ -812,19 +890,68 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
812 890
  * @ret rc		Return status code
813 891
  */
814 892
 static int tls_send_certificate ( struct tls_session *tls ) {
893
+	int num_certificates = ( have_client_certificate() ? 1 : 0 );
815 894
 	struct {
816 895
 		uint32_t type_length;
817 896
 		uint8_t length[3];
818
-	} __attribute__ (( packed )) certificate;
897
+		struct {
898
+			uint8_t length[3];
899
+			uint8_t data[ client_certificate.len ];
900
+		} __attribute__ (( packed )) certificates[num_certificates];
901
+	} __attribute__ (( packed )) *certificate;
902
+	struct x509_certificate cert;
903
+	int rc;
819 904
 
820
-	memset ( &certificate, 0, sizeof ( certificate ) );
821
-	certificate.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) |
822
-				    htonl ( sizeof ( certificate ) -
823
-					    sizeof ( certificate.type_length)));
905
+	/* If we have a certificate to send, determine the applicable
906
+	 * public-key algorithm and schedule transmission of
907
+	 * CertificateVerify.
908
+	 */
909
+	if ( num_certificates ) {
824 910
 
825
-	return tls_send_handshake ( tls, &certificate, sizeof ( certificate ) );
826
-}
911
+		/* Parse certificate to determine public-key algorithm */
912
+		if ( ( rc = x509_parse ( &cert, client_certificate.data,
913
+					 client_certificate.len ) ) != 0 ) {
914
+			DBGC ( tls, "TLS %p could not parse client "
915
+			       "certificate: %s\n", tls, strerror ( rc ) );
916
+			return rc;
917
+		}
918
+		tls->verify_pubkey = cert.signature_algorithm->pubkey;
919
+
920
+		/* Schedule CertificateVerify transmission */
921
+		tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
922
+		tls_tx_resume ( tls );
923
+	}
827 924
 
925
+	/* Allocate storage for Certificate record (which may be too
926
+	 * large for the stack).
927
+	 */
928
+	certificate = zalloc ( sizeof ( *certificate ) );
929
+	if ( ! certificate )
930
+		return -ENOMEM;
931
+
932
+	/* Populate record */
933
+	certificate->type_length =
934
+		( cpu_to_le32 ( TLS_CERTIFICATE ) |
935
+		  htonl ( sizeof ( *certificate ) -
936
+			  sizeof ( certificate->type_length ) ) );
937
+	tls_set_uint24 ( certificate->length,
938
+			 sizeof ( certificate->certificates ) );
939
+	if ( num_certificates ) {
940
+		tls_set_uint24 ( certificate->certificates[0].length,
941
+				 sizeof ( certificate->certificates[0].data ) );
942
+		memcpy ( certificate->certificates[0].data,
943
+			 client_certificate.data,
944
+			 sizeof ( certificate->certificates[0].data ) );
945
+	}
946
+
947
+	/* Transmit record */
948
+	rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
949
+
950
+	/* Free record */
951
+	free ( certificate );
952
+
953
+	return rc;
954
+}
828 955
 
829 956
 /**
830 957
  * Transmit Client Key Exchange record
@@ -866,7 +993,97 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) {
866 993
 		htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) -
867 994
 			unused );
868 995
 
869
-	return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
996
+	return tls_send_handshake ( tls, &key_xchg,
997
+				    ( sizeof ( key_xchg ) - unused ) );
998
+}
999
+
1000
+/**
1001
+ * Transmit Certificate Verify record
1002
+ *
1003
+ * @v tls		TLS session
1004
+ * @ret rc		Return status code
1005
+ */
1006
+static int tls_send_certificate_verify ( struct tls_session *tls ) {
1007
+	struct digest_algorithm *digest = tls->handshake_digest;
1008
+	struct pubkey_algorithm *pubkey = tls->verify_pubkey;
1009
+	uint8_t digest_out[ digest->digestsize ];
1010
+	uint8_t ctx[ pubkey->ctxsize ];
1011
+	struct tls_signature_hash_algorithm *sig_hash = NULL;
1012
+	int rc;
1013
+
1014
+	/* Generate digest to be signed */
1015
+	tls_verify_handshake ( tls, digest_out );
1016
+
1017
+	/* Initialise public-key algorithm */
1018
+	if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data,
1019
+				  client_private_key.len ) ) != 0 ) {
1020
+		DBGC ( tls, "TLS %p could not initialise %s client private "
1021
+		       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
1022
+		goto err_pubkey_init;
1023
+	}
1024
+
1025
+	/* TLSv1.2 and later use explicit algorithm identifiers */
1026
+	if ( tls->version >= TLS_VERSION_TLS_1_2 ) {
1027
+		sig_hash = tls_signature_hash_algorithm ( pubkey, digest );
1028
+		if ( ! sig_hash ) {
1029
+			DBGC ( tls, "TLS %p could not identify (%s,%s) "
1030
+			       "signature and hash algorithm\n", tls,
1031
+			       pubkey->name, digest->name );
1032
+			rc = -ENOTSUP;
1033
+			goto err_sig_hash;
1034
+		}
1035
+	}
1036
+
1037
+	/* Generate and transmit record */
1038
+	{
1039
+		size_t max_len = pubkey_max_len ( pubkey, ctx );
1040
+		int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 );
1041
+		struct {
1042
+			uint32_t type_length;
1043
+			struct tls_signature_hash_id sig_hash[use_sig_hash];
1044
+			uint16_t signature_len;
1045
+			uint8_t signature[max_len];
1046
+		} __attribute__ (( packed )) certificate_verify;
1047
+		size_t unused;
1048
+		int len;
1049
+
1050
+		/* Sign digest */
1051
+		len = pubkey_sign ( pubkey, ctx, digest, digest_out,
1052
+				    certificate_verify.signature );
1053
+		if ( len < 0 ) {
1054
+			rc = len;
1055
+			DBGC ( tls, "TLS %p could not sign %s digest using %s "
1056
+			       "client private key: %s\n", tls, digest->name,
1057
+			       pubkey->name, strerror ( rc ) );
1058
+			goto err_pubkey_sign;
1059
+		}
1060
+		unused = ( max_len - len );
1061
+
1062
+		/* Construct Certificate Verify record */
1063
+		certificate_verify.type_length =
1064
+			( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
1065
+			  htonl ( sizeof ( certificate_verify ) -
1066
+				  sizeof ( certificate_verify.type_length ) -
1067
+				  unused ) );
1068
+		if ( use_sig_hash ) {
1069
+			memcpy ( &certificate_verify.sig_hash[0],
1070
+				 &sig_hash->code,
1071
+				 sizeof ( certificate_verify.sig_hash[0] ) );
1072
+		}
1073
+		certificate_verify.signature_len =
1074
+			htons ( sizeof ( certificate_verify.signature ) -
1075
+				unused );
1076
+
1077
+		/* Transmit record */
1078
+		rc = tls_send_handshake ( tls, &certificate_verify,
1079
+				   ( sizeof ( certificate_verify ) - unused ) );
1080
+	}
1081
+
1082
+ err_pubkey_sign:
1083
+ err_sig_hash:
1084
+	pubkey_final ( pubkey, ctx );
1085
+ err_pubkey_init:
1086
+	return rc;
870 1087
 }
871 1088
 
872 1089
 /**
@@ -1182,9 +1399,8 @@ static int tls_new_certificate_request ( struct tls_session *tls,
1182 1399
 					 const void *data __unused,
1183 1400
 					 size_t len __unused ) {
1184 1401
 
1185
-	/* We can only send an empty certificate (as mandated by
1186
-	 * TLSv1.2), so there is no point in parsing the Certificate
1187
-	 * Request.
1402
+	/* We can only send a single certificate, so there is no point
1403
+	 * in parsing the Certificate Request.
1188 1404
 	 */
1189 1405
 
1190 1406
 	/* Schedule Certificate transmission */
@@ -2002,6 +2218,14 @@ static void tls_tx_step ( struct tls_session *tls ) {
2002 2218
 			goto err;
2003 2219
 		}
2004 2220
 		tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE;
2221
+	} else if ( tls->tx_pending & TLS_TX_CERTIFICATE_VERIFY ) {
2222
+		/* Send Certificate Verify */
2223
+		if ( ( rc = tls_send_certificate_verify ( tls ) ) != 0 ) {
2224
+			DBGC ( tls, "TLS %p could not send Certificate "
2225
+			       "Verify: %s\n", tls, strerror ( rc ) );
2226
+			goto err;
2227
+		}
2228
+		tls->tx_pending &= ~TLS_TX_CERTIFICATE_VERIFY;
2005 2229
 	} else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) {
2006 2230
 		/* Send Change Cipher, and then change the cipher in use */
2007 2231
 		if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {

Loading…
Cancel
Save