|
@@ -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
|
/**
|