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 | #ifdef WITH_TLS
|
31 |
|
32 | #ifdef WIN32
|
33 | # include <winsock2.h>
|
34 | # include <ws2tcpip.h>
|
35 | #else
|
36 | # include <arpa/inet.h>
|
37 | #endif
|
38 |
|
39 | #include <string.h>
|
40 | #include <openssl/conf.h>
|
41 | #include <openssl/x509v3.h>
|
42 | #include <openssl/ssl.h>
|
43 |
|
44 | #ifdef WITH_BROKER
|
45 | # include "mosquitto_broker.h"
|
46 | #endif
|
47 | #include "mosquitto_internal.h"
|
48 | #include "tls_mosq.h"
|
49 |
|
50 | extern int tls_ex_index_mosq;
|
51 |
|
52 | int _mosquitto_server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
53 | {
|
54 | |
55 |
|
56 | struct mosquitto *mosq;
|
57 | SSL *ssl;
|
58 | X509 *cert;
|
59 |
|
60 |
|
61 | if(!preverify_ok) return 0;
|
62 |
|
63 | ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
64 | mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq);
|
65 | if(!mosq) return 0;
|
66 |
|
67 | if(mosq->tls_insecure == false){
|
68 | if(X509_STORE_CTX_get_error_depth(ctx) == 0){
|
69 |
|
70 | cert = X509_STORE_CTX_get_current_cert(ctx);
|
71 |
|
72 | #if defined(WITH_BROKER)
|
73 | return _mosquitto_verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address);
|
74 | #else
|
75 | return _mosquitto_verify_certificate_hostname(cert, mosq->host);
|
76 | #endif
|
77 | }else{
|
78 | return preverify_ok;
|
79 | }
|
80 | }else{
|
81 | return preverify_ok;
|
82 | }
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | int _mosquitto_verify_certificate_hostname(X509 *cert, const char *hostname)
|
89 | {
|
90 | int i;
|
91 | char name[256];
|
92 | X509_NAME *subj;
|
93 | bool have_san_dns = false;
|
94 | STACK_OF(GENERAL_NAME) *san;
|
95 | const GENERAL_NAME *nval;
|
96 | const unsigned char *data;
|
97 | unsigned char ipv6_addr[16];
|
98 | unsigned char ipv4_addr[4];
|
99 | int ipv6_ok;
|
100 | int ipv4_ok;
|
101 |
|
102 | #ifdef WIN32
|
103 | ipv6_ok = InetPton(AF_INET6, hostname, &ipv6_addr);
|
104 | ipv4_ok = InetPton(AF_INET, hostname, &ipv4_addr);
|
105 | #else
|
106 | ipv6_ok = inet_pton(AF_INET6, hostname, &ipv6_addr);
|
107 | ipv4_ok = inet_pton(AF_INET, hostname, &ipv4_addr);
|
108 | #endif
|
109 |
|
110 | san = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
|
111 | if(san){
|
112 | for(i=0; i<sk_GENERAL_NAME_num(san); i++){
|
113 | nval = sk_GENERAL_NAME_value(san, i);
|
114 | if(nval->type == GEN_DNS){
|
115 | data = ASN1_STRING_data(nval->d.dNSName);
|
116 | if(data && !strcasecmp((char *)data, hostname)){
|
117 | return 1;
|
118 | }
|
119 | have_san_dns = true;
|
120 | }else if(nval->type == GEN_IPADD){
|
121 | data = ASN1_STRING_data(nval->d.iPAddress);
|
122 | if(nval->d.iPAddress->length == 4 && ipv4_ok){
|
123 | if(!memcmp(ipv4_addr, data, 4)){
|
124 | return 1;
|
125 | }
|
126 | }else if(nval->d.iPAddress->length == 16 && ipv6_ok){
|
127 | if(!memcmp(ipv6_addr, data, 16)){
|
128 | return 1;
|
129 | }
|
130 | }
|
131 | }
|
132 | }
|
133 | if(have_san_dns){
|
134 |
|
135 | return 0;
|
136 | }
|
137 | }
|
138 | subj = X509_get_subject_name(cert);
|
139 | if(X509_NAME_get_text_by_NID(subj, NID_commonName, name, sizeof(name)) > 0){
|
140 | name[sizeof(name) - 1] = '\0';
|
141 | if (!strcasecmp(name, hostname)) return 1;
|
142 | }
|
143 | return 0;
|
144 | }
|
145 |
|
146 | #endif
|
147 |
|