1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
From 272d48fe7a2ff00285d4ee166d3a9beca1d5122f Mon Sep 17 00:00:00 2001
From: Glenn Strauss <gstrauss@gluelogic.com>
Date: Sun, 23 Oct 2022 19:48:18 -0400
Subject: [PATCH 1/4] x509 crt verify SAN iPAddress
Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
---
include/mbedtls/x509_crt.h | 2 +-
library/x509_crt.c | 115 +++++++++++++++++++++++++++++--------
2 files changed, 93 insertions(+), 24 deletions(-)
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -597,7 +597,7 @@ int mbedtls_x509_crt_verify_info( char *
* \param cn The expected Common Name. This will be checked to be
* present in the certificate's subjectAltNames extension or,
* if this extension is absent, as a CN component in its
- * Subject name. Currently only DNS names are supported. This
+ * Subject name. DNS names and IP addresses are supported. This
* may be \c NULL if the CN need not be verified.
* \param flags The address at which to store the result of the verification.
* If the verification couldn't be completed, the flag value is
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -2986,6 +2986,54 @@ find_parent:
}
}
+#ifdef _WIN32
+/* ??? */
+#elif defined(__sun)
+/* Solaris requires -lsocket -lnsl for inet_pton() */
+#elif defined(__has_include)
+#if __has_include(<sys/socket.h>)
+#include <sys/socket.h>
+#endif
+#if __has_include(<arpa/inet.h>)
+#include <arpa/inet.h>
+#endif
+#endif
+
+/* Use whether or not AF_INET6 is defined to indicate whether or not to use
+ * the platform inet_pton() or a local implementation (below). The local
+ * implementation may be used even in cases where the platform provides
+ * inet_pton(), e.g. when there are different includes required and/or the
+ * platform implementation requires dependencies on additional libraries.
+ * Specifically, Windows requires custom includes and additional link
+ * dependencies, and Solaris requires additional link dependencies.
+ * Also, as a coarse heuristic, use the local implementation if the compiler
+ * does not support __has_include(), or if the definition of AF_INET6 is not
+ * provided by headers included (or not) via __has_include() above. */
+#ifndef AF_INET6
+
+#define x509_cn_inet_pton( cn, dst ) ( 0 )
+
+#else
+
+static int x509_inet_pton_ipv6( const char *src, void *dst )
+{
+ return( inet_pton( AF_INET6, src, dst ) == 1 ? 0 : -1 );
+}
+
+static int x509_inet_pton_ipv4( const char *src, void *dst )
+{
+ return( inet_pton( AF_INET, src, dst ) == 1 ? 0 : -1 );
+}
+
+#endif /* AF_INET6 */
+
+static size_t x509_cn_inet_pton( const char *cn, void *dst )
+{
+ return( strchr( cn, ':' ) == NULL
+ ? x509_inet_pton_ipv4( cn, dst ) == 0 ? 4 : 0
+ : x509_inet_pton_ipv6( cn, dst ) == 0 ? 16 : 0 );
+}
+
/*
* Check for CN match
*/
@@ -3008,23 +3056,51 @@ static int x509_crt_check_cn( const mbed
return( -1 );
}
+static int x509_crt_check_san_ip( const mbedtls_x509_sequence *san,
+ const char *cn, size_t cn_len )
+{
+ uint32_t ip[4];
+ cn_len = x509_cn_inet_pton( cn, ip );
+ if( cn_len == 0 )
+ return( -1 );
+
+ for( const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next )
+ {
+ const unsigned char san_type = (unsigned char) cur->buf.tag &
+ MBEDTLS_ASN1_TAG_VALUE_MASK;
+ if( san_type == MBEDTLS_X509_SAN_IP_ADDRESS &&
+ cur->buf.len == cn_len && memcmp( cur->buf.p, ip, cn_len ) == 0 )
+ return( 0 );
+ }
+
+ return( -1 );
+}
+
/*
* Check for SAN match, see RFC 5280 Section 4.2.1.6
*/
-static int x509_crt_check_san( const mbedtls_x509_buf *name,
+static int x509_crt_check_san( const mbedtls_x509_sequence *san,
const char *cn, size_t cn_len )
{
- const unsigned char san_type = (unsigned char) name->tag &
- MBEDTLS_ASN1_TAG_VALUE_MASK;
-
- /* dNSName */
- if( san_type == MBEDTLS_X509_SAN_DNS_NAME )
- return( x509_crt_check_cn( name, cn, cn_len ) );
-
- /* (We may handle other types here later.) */
+ int san_ip = 0;
+ for( const mbedtls_x509_sequence *cur = san; cur != NULL; cur = cur->next )
+ {
+ switch( (unsigned char) cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK )
+ {
+ case MBEDTLS_X509_SAN_DNS_NAME: /* dNSName */
+ if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 )
+ return( 0 );
+ break;
+ case MBEDTLS_X509_SAN_IP_ADDRESS: /* iPAddress */
+ san_ip = 1;
+ break;
+ /* (We may handle other types here later.) */
+ default: /* Unrecognized type */
+ break;
+ }
+ }
- /* Unrecognized type */
- return( -1 );
+ return( san_ip ? x509_crt_check_san_ip( san, cn, cn_len ) : -1 );
}
/*
@@ -3035,19 +3111,12 @@ static void x509_crt_verify_name( const
uint32_t *flags )
{
const mbedtls_x509_name *name;
- const mbedtls_x509_sequence *cur;
size_t cn_len = strlen( cn );
if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
{
- for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next )
- {
- if( x509_crt_check_san( &cur->buf, cn, cn_len ) == 0 )
- break;
- }
-
- if( cur == NULL )
- *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
+ if( x509_crt_check_san( &crt->subject_alt_names, cn, cn_len ) == 0 )
+ return;
}
else
{
@@ -3056,13 +3125,13 @@ static void x509_crt_verify_name( const
if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 &&
x509_crt_check_cn( &name->val, cn, cn_len ) == 0 )
{
- break;
+ return;
}
}
- if( name == NULL )
- *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
+
+ *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
/*
|