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
|
#include "sockhandler.h"
#include <util/datetime/base.h>
bool TSslSocketBase::Initialized = false;
sslKeys_t* TSslSocketBase::Keys = nullptr;
THolder<TSslSocketBase::TBufferAllocator> TSslSocketBase::BufAlloc;
bool TSslSocketBase::StaticInit(const char* caFile) {
Y_VERIFY(!Initialized, "SslSocket StaticInit: already initialized");
BufAlloc.Reset(new TSslSocketBase::TBufferAllocator);
if (matrixSslOpen() < 0)
Y_FAIL("SslSocket StaticInit: unable to initialize matrixSsl");
Y_VERIFY(caFile && caFile[0], "SslSocket StaticInit: no certificate authority file");
if (matrixSslReadKeys(&Keys, nullptr, nullptr, nullptr, caFile) < 0) {
Y_FAIL("SslSocket StaticInit: unable to load ssl keys from %s", caFile);
}
Initialized = true;
return Initialized;
}
bool TSslSocketBase::StaticInit(unsigned char* caBuff, int caLen) {
Y_VERIFY(!Initialized, "SslSocket StaticInit: already initialized");
BufAlloc.Reset(new TSslSocketBase::TBufferAllocator);
if (matrixSslOpen() < 0)
Y_FAIL("SslSocket StaticInit: unable to initialize matrixSsl");
Y_VERIFY(caBuff && caBuff[0] && caLen > 0, "SslSocket StaticInit: no certificate authority file");
if (matrixSslReadKeysMem(&Keys, nullptr, 0, nullptr, 0, caBuff, caLen) < 0) {
Y_FAIL("SslSocket StaticInit: unable to load ssl keys from memory");
}
Initialized = true;
return Initialized;
}
void TSslSocketBase::StaticTerm() {
Y_VERIFY(Initialized, "SslSocket StaticTerm: not initialized");
matrixSslFreeKeys(Keys);
matrixSslClose();
Keys = nullptr;
BufAlloc.Reset(nullptr);
Initialized = false;
}
bool MatchPattern(const char* p, const char* pe, const char* s, const char* se, int maxAsteriskNum) {
if (maxAsteriskNum <= 0)
return false;
while (p < pe && s < se) {
if (*p == '*') {
++p;
while (p < pe && *p == '*')
++p;
while (s < se) {
if (MatchPattern(p, pe, s, se, maxAsteriskNum - 1))
return true;
if (*s == '.')
return false;
++s;
}
return p == pe;
} else {
if (*p != *s)
return false;
++p;
++s;
}
}
while (p < pe && *p == '*')
++p;
return (p == pe && s == se);
}
bool MatchHostName(const char* pattern, size_t patternLen, const char* name, size_t nameLen) {
// rfc 2818 says:
// wildcard character * can match any single domain name component or component fragment
Y_VERIFY(name && nameLen, "Ssl certificate check error: hostname is empty");
if (!pattern || !patternLen)
return false;
const char* ne = strchr(name, ':');
if (!ne || ne > name + nameLen)
ne = name + nameLen;
return MatchPattern(pattern, pattern + patternLen, name, ne, 5);
}
bool IsExpired(const char* notBefore, const char* notAfter) {
time_t notbefore, notafter;
if (!ParseX509ValidityDateTimeDeprecated(notBefore, notbefore) || !ParseX509ValidityDateTimeDeprecated(notAfter, notafter))
return true;
time_t t = Seconds();
return notbefore > t || t > notafter;
}
int TSslSocketBase::CertChecker(sslCertInfo_t* cert, void* arg) {
Y_ASSERT(cert);
Y_ASSERT(arg);
TSocketCtx* ctx = (TSocketCtx*)arg;
ctx->CertErrors = 0;
// matching hostname
if (ctx->Host && ctx->HostLen) {
bool nameMatched = false;
sslSubjectAltNameEntry* an = cert->subjectAltName;
while (an) {
// dNSName id is 2.
if (an->id == 2 && MatchHostName((const char*)an->data, an->dataLen, ctx->Host, ctx->HostLen)) {
nameMatched = true;
break;
}
an = an->next;
}
if (!nameMatched && cert->subject.commonName) {
nameMatched = MatchHostName(cert->subject.commonName, strlen(cert->subject.commonName), ctx->Host, ctx->HostLen);
}
if (!nameMatched)
ctx->CertErrors |= SSL_CERT_HOSTNAME_MISMATCH;
}
// walk through certificate chain and check if they are signed correctly and not expired
sslCertInfo_t* c = cert;
while (c->next) {
if (IsExpired(c->notBefore, c->notAfter))
ctx->CertErrors |= SSL_CERT_EXPIRED;
if (c->verified < 0) {
ctx->CertErrors |= SSL_CERT_BAD_CHAIN;
}
c = c->next;
}
if (c->verified < 0)
ctx->CertErrors |= SSL_CERT_UNTRUSTED;
if (IsExpired(c->notBefore, c->notAfter))
ctx->CertErrors |= SSL_CERT_EXPIRED;
return SSL_ALLOW_ANON_CONNECTION;
}
|