Selaa lähdekoodia

[tls] Validate server certificate

Validate the server certificate against the trusted root certificate
store.  The server must provide a complete certificate chain, up to
and including the trusted root certificate that is embedded into iPXE.

Note that the date and time are not yet validated.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 vuotta sitten
vanhempi
commit
f3a791c6de
1 muutettua tiedostoa jossa 93 lisäystä ja 36 poistoa
  1. 93
    36
      src/net/tls.c

+ 93
- 36
src/net/tls.c Näytä tiedosto

@@ -43,6 +43,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
43 43
 #include <ipxe/rbg.h>
44 44
 #include <ipxe/tls.h>
45 45
 
46
+/* Disambiguate the various error causes */
47
+#define EACCES_UNTRUSTED \
48
+	__einfo_error ( EINFO_EACCES_UNTRUSTED )
49
+#define EINFO_EACCES_UNTRUSTED \
50
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted certificate chain" )
51
+#define EACCES_WRONG_NAME \
52
+	__einfo_error ( EINFO_EACCES_WRONG_NAME )
53
+#define EINFO_EACCES_WRONG_NAME \
54
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect server name" )
55
+
46 56
 static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
47 57
 				const void *data, size_t len );
48 58
 static void tls_clear_cipher ( struct tls_session *tls,
@@ -1003,6 +1013,63 @@ static int tls_new_server_hello ( struct tls_session *tls,
1003 1013
 	return 0;
1004 1014
 }
1005 1015
 
1016
+/** TLS certificate chain context */
1017
+struct tls_certificate_context {
1018
+	/** TLS session */
1019
+	struct tls_session *tls;
1020
+	/** Current certificate */
1021
+	const void *current;
1022
+	/** End of certificates */
1023
+	const void *end;
1024
+};
1025
+
1026
+/**
1027
+ * Parse next certificate in TLS certificate list
1028
+ *
1029
+ * @v cert		X.509 certificate to fill in
1030
+ * @v ctx		Context
1031
+ * @ret rc		Return status code
1032
+ */
1033
+static int tls_parse_next ( struct x509_certificate *cert, void *ctx ) {
1034
+	struct tls_certificate_context *context = ctx;
1035
+	struct tls_session *tls = context->tls;
1036
+	const struct {
1037
+		uint8_t length[3];
1038
+		uint8_t certificate[0];
1039
+	} __attribute__ (( packed )) *current = context->current;
1040
+	const void *data;
1041
+	const void *next;
1042
+	size_t len;
1043
+	int rc;
1044
+
1045
+	/* Return error at end of chain */
1046
+	if ( context->current >= context->end ) {
1047
+		DBGC ( tls, "TLS %p reached end of certificate chain\n", tls );
1048
+		return -EACCES_UNTRUSTED;
1049
+	}
1050
+
1051
+	/* Extract current certificate and update context */
1052
+	data = current->certificate;
1053
+	len = tls_uint24 ( current->length );
1054
+	next = ( data + len );
1055
+	if ( next > context->end ) {
1056
+		DBGC ( tls, "TLS %p overlength certificate\n", tls );
1057
+		DBGC_HDA ( tls, 0, context->current,
1058
+			   ( context->end - context->current ) );
1059
+		return -EINVAL;
1060
+	}
1061
+	context->current = next;
1062
+
1063
+	/* Parse current certificate */
1064
+	if ( ( rc = x509_parse ( cert, data, len ) ) != 0 ) {
1065
+		DBGC ( tls, "TLS %p could not parse certificate: %s\n",
1066
+		       tls, strerror ( rc ) );
1067
+		return rc;
1068
+	}
1069
+
1070
+	return 0;
1071
+}
1072
+
1006 1073
 /**
1007 1074
  * Receive new Certificate handshake record
1008 1075
  *
@@ -1017,19 +1084,14 @@ static int tls_new_certificate ( struct tls_session *tls,
1017 1084
 		uint8_t length[3];
1018 1085
 		uint8_t certificates[0];
1019 1086
 	} __attribute__ (( packed )) *certificate = data;
1020
-	const struct {
1021
-		uint8_t length[3];
1022
-		uint8_t certificate[0];
1023
-	} __attribute__ (( packed )) *element =
1024
-		  ( ( void * ) certificate->certificates );
1025 1087
 	size_t elements_len = tls_uint24 ( certificate->length );
1026 1088
 	const void *end = ( certificate->certificates + elements_len );
1027 1089
 	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
1028 1090
 	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
1091
+	struct tls_certificate_context context;
1029 1092
 	struct x509_certificate cert;
1093
+	struct x509_name *name = &cert.subject.name;
1030 1094
 	struct x509_public_key *key = &cert.subject.public_key;
1031
-	const void *cert_data;
1032
-	size_t cert_len;
1033 1095
 	int rc;
1034 1096
 
1035 1097
 	/* Sanity check */
@@ -1040,38 +1102,33 @@ static int tls_new_certificate ( struct tls_session *tls,
1040 1102
 		return -EINVAL;
1041 1103
 	}
1042 1104
 
1043
-	/* Traverse certificate chain */
1044
-	do {
1045
-		cert_data = element->certificate;
1046
-		cert_len = tls_uint24 ( element->length );
1047
-		if ( ( cert_data + cert_len ) > end ) {
1048
-			DBGC ( tls, "TLS %p received corrupt Server "
1049
-			       "Certificate\n", tls );
1050
-			DBGC_HD ( tls, data, len );
1051
-			return -EINVAL;
1052
-		}
1053
-
1054
-		// HACK
1055
-
1056
-		/* Parse certificate */
1057
-		if ( ( rc = x509_parse ( &cert, cert_data, cert_len ) ) != 0 ) {
1058
-			DBGC ( tls, "TLS %p cannot parse certificate: %s\n",
1059
-			       tls, strerror ( rc ) );
1060
-			return rc;
1061
-		}
1105
+	/* Parse first certificate and validate certificate chain */
1106
+	context.tls = tls;
1107
+	context.current = certificate->certificates;
1108
+	context.end = end;
1109
+	if ( ( rc = x509_validate_chain ( tls_parse_next, &context,
1110
+					  NULL, &cert ) ) != 0 ) {
1111
+		DBGC ( tls, "TLS %p could not validate certificate chain: %s\n",
1112
+		       tls, strerror ( rc ) );
1113
+		return rc;
1114
+	}
1062 1115
 
1063
-		/* Initialise public key algorithm */
1064
-		if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1065
-					  key->raw.data, key->raw.len ) ) != 0){
1066
-			DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1067
-			       tls, strerror ( rc ) );
1068
-			return rc;
1069
-		}
1116
+	/* Verify server name */
1117
+	if ( ( name->len != strlen ( tls->name ) ) ||
1118
+	     ( memcmp ( name->data, tls->name, name->len ) != 0 ) ) {
1119
+		DBGC ( tls, "TLS %p server name incorrect\n", tls );
1120
+		return -EACCES_WRONG_NAME;
1121
+	}
1070 1122
 
1071
-		return 0;
1072
-	} while ( element != end );
1123
+	/* Initialise public key algorithm */
1124
+	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1125
+				  key->raw.data, key->raw.len ) ) != 0 ) {
1126
+		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1127
+		       tls, strerror ( rc ) );
1128
+		return rc;
1129
+	}
1073 1130
 
1074
-	return -EINVAL;
1131
+	return 0;
1075 1132
 }
1076 1133
 
1077 1134
 /**

Loading…
Peruuta
Tallenna