Line data Source code
1 : /*
2 : * Copyright (C) 2003-2012 Free Software Foundation, Inc.
3 : * Copyright (C) 2002 Andrew McDonald
4 : *
5 : * This file is part of GnuTLS.
6 : *
7 : * The GnuTLS is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU Lesser General Public License
9 : * as published by the Free Software Foundation; either version 2.1 of
10 : * the License, or (at your option) any later version.
11 : *
12 : * This library is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public License
18 : * along with this program. If not, see <https://www.gnu.org/licenses/>
19 : *
20 : */
21 :
22 : #include "gnutls_int.h"
23 : #include <str.h>
24 : #include <x509_int.h>
25 : #include <common.h>
26 : #include "errors.h"
27 : #include <system.h>
28 :
29 : /**
30 : * gnutls_x509_crt_check_email:
31 : * @cert: should contain an gnutls_x509_crt_t type
32 : * @email: A null terminated string that contains an email address (RFC822)
33 : * @flags: should be zero
34 : *
35 : * This function will check if the given certificate's subject matches
36 : * the given email address.
37 : *
38 : * Returns: non-zero for a successful match, and zero on failure.
39 : **/
40 : unsigned
41 8 : gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
42 : const char *email, unsigned int flags)
43 : {
44 8 : char rfc822name[MAX_CN];
45 8 : size_t rfc822namesize;
46 8 : int found_rfc822name = 0;
47 8 : int ret = 0;
48 8 : int i = 0;
49 8 : char *a_email;
50 8 : gnutls_datum_t out;
51 :
52 : /* convert the provided email to ACE-Labels domain. */
53 8 : ret = _gnutls_idna_email_map(email, strlen(email), &out);
54 8 : if (ret < 0) {
55 0 : _gnutls_debug_log("unable to convert email %s to IDNA format\n", email);
56 : a_email = (char*)email;
57 : } else {
58 8 : a_email = (char*)out.data;
59 : }
60 :
61 : /* try matching against:
62 : * 1) an address as an alternative name (subjectAltName) extension
63 : * in the certificate
64 : * 2) the EMAIL field in the certificate
65 : *
66 : * only try (2) if there is no subjectAltName extension of
67 : * type RFC822Name, and there is a single EMAIL.
68 : */
69 :
70 : /* Check through all included subjectAltName extensions, comparing
71 : * against all those of type RFC822Name.
72 : */
73 16 : for (i = 0; !(ret < 0); i++) {
74 :
75 12 : rfc822namesize = sizeof(rfc822name);
76 12 : ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
77 : rfc822name,
78 : &rfc822namesize,
79 : NULL);
80 :
81 12 : if (ret == GNUTLS_SAN_RFC822NAME) {
82 8 : found_rfc822name = 1;
83 :
84 8 : if (_gnutls_has_embedded_null(rfc822name, rfc822namesize)) {
85 0 : _gnutls_debug_log("certificate has %s with embedded null in rfc822name\n", rfc822name);
86 0 : continue;
87 : }
88 :
89 130 : if (!_gnutls_str_is_print(rfc822name, rfc822namesize)) {
90 0 : _gnutls_debug_log("invalid (non-ASCII) email in certificate %.*s\n", (int)rfc822namesize, rfc822name);
91 0 : continue;
92 : }
93 :
94 8 : ret = _gnutls_hostname_compare(rfc822name, rfc822namesize, a_email, GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
95 8 : if (ret != 0) {
96 4 : ret = 1;
97 4 : goto cleanup;
98 : }
99 : }
100 : }
101 :
102 4 : if (!found_rfc822name) {
103 : /* did not get the necessary extension, use CN instead
104 : */
105 :
106 : /* enforce the RFC6125 (ยง1.8) requirement that only
107 : * a single CN must be present */
108 0 : rfc822namesize = sizeof(rfc822name);
109 0 : ret = gnutls_x509_crt_get_dn_by_oid
110 : (cert, GNUTLS_OID_PKCS9_EMAIL, 1, 0, rfc822name,
111 : &rfc822namesize);
112 0 : if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
113 0 : ret = 0;
114 0 : goto cleanup;
115 : }
116 :
117 0 : rfc822namesize = sizeof(rfc822name);
118 0 : ret = gnutls_x509_crt_get_dn_by_oid
119 : (cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, rfc822name,
120 : &rfc822namesize);
121 0 : if (ret < 0) {
122 0 : ret = 0;
123 0 : goto cleanup;
124 : }
125 :
126 0 : if (_gnutls_has_embedded_null(rfc822name, rfc822namesize)) {
127 0 : _gnutls_debug_log("certificate has EMAIL %s with embedded null in name\n", rfc822name);
128 0 : ret = 0;
129 0 : goto cleanup;
130 : }
131 :
132 0 : if (!_gnutls_str_is_print(rfc822name, rfc822namesize)) {
133 0 : _gnutls_debug_log("invalid (non-ASCII) email in certificate DN %.*s\n", (int)rfc822namesize, rfc822name);
134 0 : ret = 0;
135 0 : goto cleanup;
136 : }
137 :
138 0 : ret = _gnutls_hostname_compare(rfc822name, rfc822namesize, a_email, GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
139 0 : if (ret != 0) {
140 0 : ret = 1;
141 0 : goto cleanup;
142 : }
143 : }
144 :
145 : /* not found a matching name
146 : */
147 : ret = 0;
148 8 : cleanup:
149 8 : if (a_email != email) {
150 8 : gnutls_free(a_email);
151 : }
152 8 : return ret;
153 : }
|