@@ -4,8 +4,37 @@ from sha1 import Sha1Digest
4
4
from nimSHA2 import Sha224Digest , Sha256Digest , Sha384Digest , Sha512Digest
5
5
6
6
7
- proc SSL_get_finished * (ssl: SslPtr , buf: cstring , count: csize_t ): csize_t {.cdecl , dynlib : DLLSSLName , importc .}
8
- proc SSL_get_peer_finished * (ssl: SslPtr , buf: cstring , count: csize_t ): csize_t {.cdecl , dynlib : DLLSSLName , importc .}
7
+ # from net import Socket
8
+ # from asyncnet import AsyncSocket
9
+
10
+ # export Socket, AsyncSocket
11
+
12
+ type
13
+ AnySocket * = Socket | AsyncSocket
14
+
15
+ const
16
+ NID_md5 = 4
17
+ NID_md5_sha1 = 114
18
+ EVP_MAX_MD_SIZE = 64
19
+
20
+ {.push cdecl , dynlib : DLLSSLName , importc .}
21
+
22
+ proc SSL_get_finished (ssl: SslPtr , buf: cstring , count: csize_t ): csize_t
23
+ proc SSL_get_peer_finished (ssl: SslPtr , buf: cstring , count: csize_t ): csize_t
24
+
25
+ proc SSL_get_certificate (ssl: SslPtr ): PX509
26
+ proc SSL_get_peer_certificate (ssl: SslPtr ): PX509
27
+
28
+ proc X509_get_signature_nid (x: PX509 ): int32
29
+ proc OBJ_find_sigid_algs (signature: int32 , pdigest: pointer , pencryption: pointer ): int32
30
+ proc OBJ_nid2sn (n: int ): cstring
31
+
32
+ proc EVP_sha256 (): PEVP_MD
33
+ proc EVP_get_digestbynid (): PEVP_MD
34
+
35
+ proc X509_digest (data: PX509 , kind: PEVP_MD , md: ptr char , len: ptr uint32 ): int32
36
+
37
+ {.pop .}
9
38
10
39
randomize ()
11
40
@@ -104,30 +133,67 @@ proc makeCBind*(channel: ChannelType, data: string = ""): string =
104
133
result = " c=" & base64.encode (makeGS2Header (channel) & data)
105
134
106
135
107
- proc validateCB * (channel: ChannelType , socket: AnySocket ) =
136
+ proc validateChannelBinding * (channel: ChannelType , socket: AnySocket ) =
108
137
if channel == TLS_NONE :
109
138
return
110
139
111
140
if channel > TLS_EXPORT :
112
- raise newException (ScramChannelBindingError , " Channel type " & $ channel & " is not supported" )
141
+ raise newException (ScramError , " Channel type " & $ channel & " is not supported" )
113
142
114
143
if socket.isNil:
115
- raise newException (ScramChannelBindingError , " Socket is not initialized" )
144
+ raise newException (ScramError , " Socket is not initialized" )
116
145
117
146
if not socket.isSsl or socket.sslHandle () == nil :
118
- raise newException (ScramChannelBindingError , " Socket is not wrapped in a SSL context" )
147
+ raise newException (ScramError , " Socket is not wrapped in a SSL context" )
148
+
149
+ proc getChannelBindingData * (channel: ChannelType , socket: AnySocket , isServer = true ): string =
150
+ # Ref: https://paquier.xyz/postgresql-2/channel-binding-openssl/
119
151
120
- proc getCBData * (channel: ChannelType , socket: AnySocket , isServer = true ): string =
152
+ validateChannelBinding (channel, socket)
121
153
122
- result = newString (1024 )
154
+ result = newString (EVP_MAX_MD_SIZE )
123
155
if channel == TLS_UNIQUE :
124
156
var ret: csize_t
125
157
if isServer:
126
- ret = SSL_get_peer_finished (socket.sslHandle (), result .cstring , 1024 )
158
+ ret = SSL_get_peer_finished (socket.sslHandle (), result .cstring , EVP_MAX_MD_SIZE )
127
159
else :
128
- ret = SSL_get_finished (socket.sslHandle (), result .cstring , 1024 )
160
+ ret = SSL_get_finished (socket.sslHandle (), result .cstring , EVP_MAX_MD_SIZE )
129
161
130
162
if ret == 0 :
131
- raise newException (ScramChannelBindingError , " SSLError: handshake has not reached the finished message" )
132
-
163
+ raise newException (ScramError , " SSLError: handshake has not reached the finished message" )
133
164
result .setLen (ret)
165
+
166
+ elif channel == TLS_SERVER_END_POINT :
167
+ var
168
+ serverCert: PX509
169
+ algoNid: int32
170
+ algoType: PEVP_MD
171
+ hash: array [EVP_MAX_MD_SIZE , char ]
172
+ hashSize: int32
173
+
174
+ if isServer:
175
+ serverCert = cast [PX509 ](SSL_get_certificate (socket.sslHandle ()))
176
+ else :
177
+ serverCert = cast [PX509 ](SSL_get_peer_certificate (socket.sslHandle ()))
178
+
179
+ if serverCert == nil :
180
+ raise newException (ScramError , " SSLError: could not load server certtificate" )
181
+
182
+ if OBJ_find_sigid_algs (X509_get_signature_nid (serverCert), addr algoNid, nil ) == 0 :
183
+ raise newException (ScramError , " SSLError: could not determine server certificate signature algorithm" )
184
+
185
+ if algoNid == NID_md5 or algoNid == NID_md5_sha1:
186
+ algoType = EVP_sha256 ()
187
+ else :
188
+ algoType = EVP_get_digestbynid (algoNid)
189
+ if algoType == nil :
190
+ raise newException (ScramError , " SSLError: could not find digest for NID " & OBJ_nid2sn (algoNid))
191
+
192
+ if X509_digest (serverCert, algoType, hash, addr hashSize) == 0 :
193
+ raise newException (ScramError , " SSLError: could not generate server certificate hash" )
194
+
195
+ copyMem (addr result [0 ], hash, hashSize)
196
+ result .setLen (hashSize)
197
+
198
+ else :
199
+ raise newException (ScramError , " Channel " & $ channel & " is not supported yet" )
0 commit comments