summaryrefslogtreecommitdiff
path: root/src/lib/libressl/ressl_verify.c
diff options
context:
space:
mode:
authorjsing <>2014-07-12 01:20:25 +0000
committerjsing <>2014-07-12 01:20:25 +0000
commit2b0153d4f076d501b21de2e54937a5bb1b139635 (patch)
treecb217fd8fb935cea61fc26de366b7e407229df65 /src/lib/libressl/ressl_verify.c
parentc95157e4b6c5e281cb496ef41f9969df25abef91 (diff)
downloadopenbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.tar.gz
openbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.tar.bz2
openbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.zip
Initial version of libressl - a library that provides a clean, simple,
consistent and secure-by-default API for SSL clients (and soon servers). This is a long way from complete and the interface will likely change substantially - committing now so that further work can happen in the tree. Initiated by tedu@ and inspired by discussions with tedu@, beck@ and other developers.
Diffstat (limited to 'src/lib/libressl/ressl_verify.c')
-rw-r--r--src/lib/libressl/ressl_verify.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/lib/libressl/ressl_verify.c b/src/lib/libressl/ressl_verify.c
new file mode 100644
index 0000000000..e98a264f4f
--- /dev/null
+++ b/src/lib/libressl/ressl_verify.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/socket.h>
18
19#include <arpa/inet.h>
20#include <netinet/in.h>
21
22#include <string.h>
23
24#include <openssl/x509v3.h>
25
26#include "ressl_internal.h"
27
28int ressl_match_hostname(const char *cert_hostname, const char *hostname);
29int ressl_check_subject_altname(X509 *cert, const char *host);
30int ressl_check_common_name(X509 *cert, const char *host);
31
32int
33ressl_match_hostname(const char *cert_hostname, const char *hostname)
34{
35 const char *cert_domain, *domain;
36
37 if (strcasecmp(cert_hostname, hostname) == 0)
38 return 0;
39
40 /* Wildcard match? */
41 if (cert_hostname[0] == '*') {
42 cert_domain = &cert_hostname[1];
43 if (cert_domain[0] != '.')
44 return -1;
45 if (strlen(cert_domain) == 1)
46 return -1;
47
48 domain = strchr(hostname, '.');
49
50 /* No wildcard match against a hostname with no domain part. */
51 if (domain == NULL || strlen(domain) == 1)
52 return -1;
53
54 if (strcasecmp(cert_domain, domain) == 0)
55 return 0;
56 }
57
58 return -1;
59}
60
61int
62ressl_check_subject_altname(X509 *cert, const char *host)
63{
64 STACK_OF(GENERAL_NAME) *altname_stack = NULL;
65 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
66 int addrlen, type;
67 int count, i;
68 int rv = -1;
69
70 altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
71 NULL, NULL);
72 if (altname_stack == NULL)
73 return -1;
74
75 if (inet_pton(AF_INET, host, &addrbuf) == 1) {
76 type = GEN_IPADD;
77 addrlen = 4;
78 } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) {
79 type = GEN_IPADD;
80 addrlen = 16;
81 } else {
82 type = GEN_DNS;
83 addrlen = 0;
84 }
85
86 count = sk_GENERAL_NAME_num(altname_stack);
87 for (i = 0; i < count; i++) {
88 GENERAL_NAME *altname;
89
90 altname = sk_GENERAL_NAME_value(altname_stack, i);
91
92 if (altname->type != type)
93 continue;
94
95 if (type == GEN_DNS) {
96 unsigned char *data;
97 int format;
98
99 format = ASN1_STRING_type(altname->d.dNSName);
100 if (format == V_ASN1_IA5STRING) {
101 data = ASN1_STRING_data(altname->d.dNSName);
102
103 if (ASN1_STRING_length(altname->d.dNSName) !=
104 (int)strlen(data)) {
105 fprintf(stdout, "%s: NUL byte in "
106 "subjectAltName, probably a "
107 "malicious certificate.\n",
108 getprogname());
109 rv = -2;
110 break;
111 }
112
113 if (ressl_match_hostname(data, host) == 0) {
114 rv = 0;
115 break;
116 }
117 } else
118 fprintf(stdout, "%s: unhandled subjectAltName "
119 "dNSName encoding (%d)\n", getprogname(),
120 format);
121
122 } else if (type == GEN_IPADD) {
123 unsigned char *data;
124 int datalen;
125
126 datalen = ASN1_STRING_length(altname->d.iPAddress);
127 data = ASN1_STRING_data(altname->d.iPAddress);
128
129 if (datalen == addrlen &&
130 memcmp(data, &addrbuf, addrlen) == 0) {
131 rv = 0;
132 break;
133 }
134 }
135 }
136
137 sk_GENERAL_NAME_free(altname_stack);
138 return rv;
139}
140
141int
142ressl_check_common_name(X509 *cert, const char *host)
143{
144 X509_NAME *name;
145 char *common_name = NULL;
146 size_t common_name_len;
147 int rv = -1;
148
149 name = X509_get_subject_name(cert);
150 if (name == NULL)
151 goto out;
152
153 common_name_len = X509_NAME_get_text_by_NID(name, NID_commonName,
154 NULL, 0);
155 if (common_name_len < 0)
156 goto out;
157
158 common_name = calloc(common_name_len + 1, 1);
159 if (common_name == NULL)
160 goto out;
161
162 X509_NAME_get_text_by_NID(name, NID_commonName, common_name,
163 common_name_len + 1);
164
165 /* NUL bytes in CN? */
166 if (common_name_len != (int)strlen(common_name)) {
167 fprintf(stdout, "%s: NUL byte in Common Name field, "
168 "probably a malicious certificate.\n", getprogname());
169 rv = -2;
170 goto out;
171 }
172
173 if (ressl_match_hostname(common_name, host) == 0)
174 rv = 0;
175out:
176 free(common_name);
177 return rv;
178}
179
180int
181ressl_check_hostname(X509 *cert, const char *host)
182{
183 int rv;
184
185 rv = ressl_check_subject_altname(cert, host);
186 if (rv == 0 || rv == -2)
187 return rv;
188
189 return ressl_check_common_name(cert, host);
190}