/
cTlsSocket.cls
2439 lines (2252 loc) · 89.1 KB
/
cTlsSocket.cls
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "cTlsSocket"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'=========================================================================
'
' VbAsyncSocket Project (c) 2018-2020 by wqweto@gmail.com
'
' Simple and thin WinSock API wrappers for VB6
'
' This project is licensed under the terms of the MIT license
' See the LICENSE file in the project root for more information
'
'=========================================================================
Option Explicit
DefObj A-Z
Private Const MODULE_NAME As String = "cTlsSocket"
#Const ImplUseShared = (ASYNCSOCKET_USE_SHARED <> 0)
#Const ImplSync = Not (ASYNCSOCKET_NO_SYNC <> 0)
#Const ImplUseDebugLog = (USE_DEBUG_LOG <> 0)
'=========================================================================
' Public events
'=========================================================================
Event OnResolve(IpAddress As String)
Event OnAccept()
Event OnClose()
Event OnConnect()
Event OnReceive()
Event OnSend()
Event OnError(ByVal ErrorCode As Long, ByVal EventMask As UcsAsyncSocketEventMaskEnum)
Event OnMessagePending(Handled As Boolean)
Event BeforeNotify(ByVal EventMask As UcsAsyncSocketEventMaskEnum, Cancel As Boolean)
Event AfterNotify(ByVal EventMask As UcsAsyncSocketEventMaskEnum)
Event OnClientCertificate(Issuers As Object, Confirmed As Boolean)
Public Enum UcsTlsLocalFeaturesEnum '--- bitmask
ucsTlsSupportTls10 = 2 ^ 0
ucsTlsSupportTls11 = 2 ^ 1
ucsTlsSupportTls12 = 2 ^ 2
ucsTlsSupportTls13 = 2 ^ 3
ucsTlsIgnoreServerCertificateErrors = 2 ^ 4
ucsTlsIgnoreServerCertificateRevocation = 2 ^ 5
ucsTlsSupportAll = ucsTlsSupportTls10 Or ucsTlsSupportTls11 Or ucsTlsSupportTls12 Or ucsTlsSupportTls13
End Enum
'=========================================================================
' API
'=========================================================================
'--- for CryptAcquireContext
Private Const PROV_RSA_FULL As Long = 1
Private Const CRYPT_NEWKEYSET As Long = &H8
Private Const CRYPT_DELETEKEYSET As Long = &H10
'--- for CryptDecodeObjectEx
Private Const X509_ASN_ENCODING As Long = 1
Private Const PKCS_7_ASN_ENCODING As Long = &H10000
Private Const PKCS_RSA_PRIVATE_KEY As Long = 43
Private Const PKCS_PRIVATE_KEY_INFO As Long = 44
Private Const X509_ECC_PRIVATE_KEY As Long = 82
Private Const CNG_RSA_PRIVATE_KEY_BLOB As Long = 83
Private Const CRYPT_DECODE_NOCOPY_FLAG As Long = &H1
Private Const CRYPT_DECODE_ALLOC_FLAG As Long = &H8000
'--- for CryptSignHash
Private Const AT_SIGNATURE As Long = 2
Private Const RSA1024BIT_KEY As Long = &H4000000
Private Const NTE_BAD_ALGID As Long = &H80090008
'--- for CertGetCertificateContextProperty
Private Const CERT_KEY_PROV_INFO_PROP_ID As Long = 2
'--- for PFXImportCertStore
Private Const CRYPT_EXPORTABLE As Long = &H1
'--- for CryptExportKey
Private Const PRIVATEKEYBLOB As Long = 7
'--- for CryptAcquireCertificatePrivateKey
Private Const CRYPT_ACQUIRE_CACHE_FLAG As Long = &H1
Private Const CRYPT_ACQUIRE_SILENT_FLAG As Long = &H40
Private Const CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG As Long = &H10000
'--- for NCryptImportKey
Private Const NCRYPT_OVERWRITE_KEY_FLAG As Long = &H80
Private Const NCRYPT_DO_NOT_FINALIZE_FLAG As Long = &H400
'--- for NCryptSetProperty
Private Const NCRYPT_PERSIST_FLAG As Long = &H80000000
'--- for CertStrToName
Private Const CERT_OID_NAME_STR As Long = 2
'--- for CertOpenStore
Private Const CERT_STORE_PROV_MEMORY As Long = 2
Private Const CERT_STORE_CREATE_NEW_FLAG As Long = &H2000
'--- for CertAddEncodedCertificateToStore
Private Const CERT_STORE_ADD_USE_EXISTING As Long = 2
'--- for CertGetCertificateChain
Private Const CERT_CHAIN_REVOCATION_CHECK_CHAIN As Long = &H20000000
Private Const CERT_TRUST_IS_NOT_TIME_VALID As Long = &H1
Private Const CERT_TRUST_IS_NOT_TIME_NESTED As Long = &H2
Private Const CERT_TRUST_IS_REVOKED As Long = &H4
Private Const CERT_TRUST_IS_NOT_SIGNATURE_VALID As Long = &H8
Private Const CERT_TRUST_IS_UNTRUSTED_ROOT As Long = &H20
Private Const CERT_TRUST_REVOCATION_STATUS_UNKNOWN As Long = &H40
Private Const CERT_TRUST_IS_PARTIAL_CHAIN As Long = &H10000
'--- for CertFindCertificateInStore
Private Const CERT_FIND_EXISTING As Long = &HD0000
'--- for CERT_ALT_NAME_ENTRY
Private Const CERT_ALT_NAME_DNS_NAME As Long = 3
'--- for CertCreateCertificateChainEngine
Private Const CERT_CHAIN_CACHE_END_CERT As Long = 1
'--- OIDs
Private Const szOID_RSA_RSA As String = "1.2.840.113549.1.1.1"
Private Const szOID_ECC_CURVE_P256 As String = "1.2.840.10045.3.1.7"
Private Const szOID_ECC_CURVE_P384 As String = "1.3.132.0.34"
Private Const szOID_ECC_CURVE_P521 As String = "1.3.132.0.35"
Private Const szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES As String = "1.2.840.113549.1.12.1.3"
Private Const szOID_SUBJECT_ALT_NAME2 As String = "2.5.29.17"
'--- BLOBs magic
Private Const BCRYPT_RSAPRIVATE_MAGIC As Long = &H32415352
Private Const BCRYPT_ECDH_PRIVATE_P256_MAGIC As Long = &H324B4345
Private Const BCRYPT_ECDH_PRIVATE_P384_MAGIC As Long = &H344B4345
Private Const BCRYPT_ECDH_PRIVATE_P521_MAGIC As Long = &H364B4345
'--- buffer types
Private Const NCRYPTBUFFER_PKCS_ALG_OID As Long = 41
Private Const NCRYPTBUFFER_PKCS_ALG_PARAM As Long = 42
Private Const NCRYPTBUFFER_PKCS_KEY_NAME As Long = 45
Private Const NCRYPTBUFFER_PKCS_SECRET As Long = 46
'--- export policy flags
Private Const NCRYPT_ALLOW_EXPORT_FLAG As Long = &H1
Private Const NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG As Long = &H2
Private Const ERR_TIMEOUT As Long = &H800705B4
Private Const INVALID_SOCKET As Long = -1
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Ptr() As Any) As Long
Private Declare Function IsBadReadPtr Lib "kernel32" (ByVal lp As Long, ByVal ucb As Long) As Long
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As Any) As Long
'--- advapi32
Private Declare Function CryptAcquireContext Lib "advapi32" Alias "CryptAcquireContextW" (phProv As Long, ByVal pszContainer As Long, ByVal pszProvider As Long, ByVal dwProvType As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptReleaseContext Lib "advapi32" (ByVal hProv As Long, ByVal dwFlags As Long) As Long
Private Declare Function CryptGenKey Lib "advapi32" (ByVal hProv As Long, ByVal AlgId As Long, ByVal dwFlags As Long, phKey As Long) As Long
Private Declare Function CryptDestroyKey Lib "advapi32" (ByVal hKey As Long) As Long
Private Declare Function CryptGetUserKey Lib "advapi32" (ByVal hProv As Long, ByVal dwKeySpec As Long, phUserKey As Long) As Long
Private Declare Function CryptExportKey Lib "advapi32" (ByVal hKey As Long, ByVal hExpKey As Long, ByVal dwBlobType As Long, ByVal dwFlags As Long, pbData As Any, pdwDataLen As Long) As Long
'--- Crypt32
Private Declare Function CryptDecodeObjectEx Lib "crypt32" (ByVal dwCertEncodingType As Long, ByVal lpszStructType As Any, pbEncoded As Any, ByVal cbEncoded As Long, ByVal dwFlags As Long, ByVal pDecodePara As Long, pvStructInfo As Any, pcbStructInfo As Long) As Long
Private Declare Function CryptEncodeObjectEx Lib "crypt32" (ByVal dwCertEncodingType As Long, ByVal lpszStructType As Any, pvStructInfo As Any, ByVal dwFlags As Long, ByVal pEncodePara As Long, pvEncoded As Any, pcbEncoded As Long) As Long
Private Declare Function CryptAcquireCertificatePrivateKey Lib "crypt32" (ByVal pCert As Long, ByVal dwFlags As Long, ByVal pvParameters As Long, phCryptProvOrNCryptKey As Long, pdwKeySpec As Long, pfCallerFreeProvOrNCryptKey As Long) As Long
Private Declare Function PFXImportCertStore Lib "crypt32" (pPFX As Any, ByVal szPassword As Long, ByVal dwFlags As Long) As Long
Private Declare Function CertFreeCertificateContext Lib "crypt32" (ByVal pCertContext As Long) As Long
Private Declare Function CertEnumCertificatesInStore Lib "crypt32" (ByVal hCertStore As Long, ByVal pPrevCertContext As Long) As Long
Private Declare Function CertGetCertificateContextProperty Lib "crypt32" (ByVal pCertContext As Long, ByVal dwPropId As Long, pvData As Any, pcbData As Long) As Long
Private Declare Function CertStrToName Lib "crypt32" Alias "CertStrToNameW" (ByVal dwCertEncodingType As Long, ByVal pszX500 As Long, ByVal dwStrType As Long, ByVal pvReserved As Long, pbEncoded As Any, pcbEncoded As Long, ByVal ppszError As Long) As Long
Private Declare Function CertCreateSelfSignCertificate Lib "crypt32" (ByVal hCryptProvOrNCryptKey As Long, pSubjectIssuerBlob As Any, ByVal dwFlags As Long, pKeyProvInfo As Any, ByVal pSignatureAlgorithm As Long, pStartTime As Any, pEndTime As Any, ByVal pExtensions As Long) As Long
Private Declare Function CertOpenStore Lib "crypt32" (ByVal lpszStoreProvider As Long, ByVal dwEncodingType As Long, ByVal hCryptProv As Long, ByVal dwFlags As Long, ByVal pvPara As Long) As Long
Private Declare Function CertCloseStore Lib "crypt32" (ByVal hCertStore As Long, ByVal dwFlags As Long) As Long
Private Declare Function CertAddEncodedCertificateToStore Lib "crypt32" (ByVal hCertStore As Long, ByVal dwCertEncodingType As Long, pbCertEncoded As Any, ByVal cbCertEncoded As Long, ByVal dwAddDisposition As Long, ByVal ppCertContext As Long) As Long
Private Declare Function CertCreateCertificateChainEngine Lib "crypt32" (pConfig As Any, phChainEngine As Long) As Long
Private Declare Function CertFreeCertificateChainEngine Lib "crypt32" (ByVal hChainEngine As Long) As Long
Private Declare Function CertGetCertificateChain Lib "crypt32" (ByVal hChainEngine As Long, ByVal pCertContext As Long, ByVal pTime As Long, ByVal hAdditionalStore As Long, pChainPara As Any, ByVal dwFlags As Long, ByVal pvReserved As Long, ppChainContext As Long) As Long
Private Declare Function CertFreeCertificateChain Lib "crypt32" (ByVal pChainContext As Long) As Long
Private Declare Function CertFindExtension Lib "crypt32" (ByVal pszObjId As String, ByVal cExtensions As Long, ByVal rgExtensions As Long) As Long
Private Declare Function CertFindCertificateInStore Lib "crypt32" (ByVal hCertStore As Long, ByVal dwCertEncodingType As Long, ByVal dwFindFlags As Long, ByVal dwFindType As Long, pvFindPara As Any, ByVal pPrevCertContext As Long) As Long
'--- NCrypt
Private Declare Function NCryptImportKey Lib "ncrypt" (ByVal hProvider As Long, ByVal hImportKey As Long, ByVal pszBlobType As Long, pParameterList As Any, phKey As Long, pbData As Any, ByVal cbData As Long, ByVal dwFlags As Long) As Long
Private Declare Function NCryptExportKey Lib "ncrypt" (ByVal hKey As Long, ByVal hExportKey As Long, ByVal pszBlobType As Long, pParameterList As Any, pbOutput As Any, ByVal cbOutput As Long, pcbResult As Any, ByVal dwFlags As Long) As Long
Private Declare Function NCryptFreeObject Lib "ncrypt" (ByVal hKey As Long) As Long
Private Declare Function NCryptGetProperty Lib "ncrypt" (ByVal hObject As Long, ByVal pszProperty As Long, pbOutput As Any, ByVal cbOutput As Long, pcbResult As Long, ByVal dwFlags As Long) As Long
Private Declare Function NCryptSetProperty Lib "ncrypt" (ByVal hObject As Long, ByVal pszProperty As Long, pbInput As Any, ByVal cbInput As Long, ByVal dwFlags As Long) As Long
Private Declare Function NCryptFinalizeKey Lib "ncrypt" (ByVal hKey As Long, ByVal dwFlags As Long) As Long
#If Not ImplUseShared Then
Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
#End If
Private Type CRYPT_BLOB_DATA
cbData As Long
pbData As Long
End Type
Private Type CRYPT_BIT_BLOB
cbData As Long
pbData As Long
cUnusedBits As Long
End Type
Private Type CRYPT_ALGORITHM_IDENTIFIER
pszObjId As Long
Parameters As CRYPT_BLOB_DATA
End Type
Private Type CERT_PUBLIC_KEY_INFO
Algorithm As CRYPT_ALGORITHM_IDENTIFIER
PublicKey As CRYPT_BIT_BLOB
End Type
Private Type CRYPT_ECC_PRIVATE_KEY_INFO
dwVersion As Long
PrivateKey As CRYPT_BLOB_DATA
szCurveOid As Long
PublicKey As CRYPT_BLOB_DATA
End Type
Private Type CRYPT_KEY_PROV_INFO
pwszContainerName As Long
pwszProvName As Long
dwProvType As Long
dwFlags As Long
cProvParam As Long
rgProvParam As Long
dwKeySpec As Long
End Type
Private Type CERT_CONTEXT
dwCertEncodingType As Long
pbCertEncoded As Long
cbCertEncoded As Long
pCertInfo As Long
hCertStore As Long
End Type
Private Type CRYPT_PRIVATE_KEY_INFO
dwVersion As Long
Algorithm As CRYPT_ALGORITHM_IDENTIFIER
PrivateKey As CRYPT_BLOB_DATA
pAttributes As Long
End Type
Private Type CRYPT_PKCS12_PBE_PARAMS
iIterations As Long
cbSalt As Long
SaltBuffer(0 To 31) As Byte
End Type
Private Type CERT_ALT_NAME_ENTRY
dwAltNameChoice As Long
pwszDNSName As Long
Padding As Long
End Type
Private Type CERT_ALT_NAME_INFO
cAltEntry As Long
rgAltEntry As Long
End Type
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type CERT_INFO
dwVersion As Long
SerialNumber As CRYPT_BLOB_DATA
SignatureAlgorithm As CRYPT_ALGORITHM_IDENTIFIER
Issuer As CRYPT_BLOB_DATA
NotBefore As FILETIME
NotAfter As FILETIME
Subject As CRYPT_BLOB_DATA
SubjectPublicKeyInfo As CERT_PUBLIC_KEY_INFO
IssuerUniqueId As CRYPT_BIT_BLOB
SubjectUniqueId As CRYPT_BIT_BLOB
cExtension As Long
rgExtension As Long
End Type
Private Type CERT_TRUST_STATUS
dwErrorStatus As Long
dwInfoStatus As Long
End Type
Private Type CERT_CHAIN_CONTEXT
cbSize As Long
TrustStatus As CERT_TRUST_STATUS
cElems As Long
rgElem As Long
'--- more here
End Type
Private Type CTL_USAGE
cUsageIdentifier As Long
rgpszUsageIdentifier As Long
End Type
Private Type CERT_USAGE_MATCH
dwType As Long
Usage As CTL_USAGE
End Type
Private Type CERT_CHAIN_PARA
cbSize As Long
RequestedUsage As CERT_USAGE_MATCH
End Type
Private Type CERT_EXTENSION
pszObjId As Long
fCritical As Long
Value As CRYPT_BLOB_DATA
End Type
Private Type NCryptBuffer
cbBuffer As Long
BufferType As Long
pvBuffer As Long
End Type
Private Type NCryptBufferDesc
ulVersion As Long
cBuffers As Long
pBuffers As Long
Buffers() As NCryptBuffer
End Type
Private Type CERT_CHAIN_ENGINE_CONFIG
cbSize As Long
hRestrictedRoot As Long
hRestrictedTrust As Long
hRestrictedOther As Long
cAdditionalStore As Long
rghAdditionalStore As Long
dwFlags As Long
dwUrlRetrievalTimeout As Long
MaximumCachedCertificates As Long
CycleDetectionModulus As Long
'--- following are Win7+ only
hExclusiveRoot As Long
hExclusiveTrustedPeople As Long
dwExclusiveFlags As Long
End Type
Private Type CERT_CHAIN_ELEMENT
cbSize As Long
pCertContext As Long
TrustStatus As CERT_TRUST_STATUS
pRevocationInfo As Long
pIssuanceUsage As Long
pApplicationUsage As Long
pwszExtendedErrorInfo As Long
End Type
'=========================================================================
' Constants and member variables
'=========================================================================
Private Const STR_CHR1 As String = "" '--- CHAR(1)
Private Const DEF_TIMEOUT As Long = 5000
Private Const LNG_FACILITY_WIN32 As Long = &H80070000
'--- errors
Private Const ERR_NO_MATCHING_ALT_NAME As String = "No certificate subject name matches target host name"
Private Const ERR_NO_CERTIFICATE As String = "No server certificate found"
Private Const ERR_TRUST_IS_REVOKED As String = "Trust for this certificate or one of the certificates in the certificate chain has been revoked"
Private Const ERR_TRUST_IS_PARTIAL_CHAIN As String = "The certificate chain is not complete"
Private Const ERR_TRUST_IS_UNTRUSTED_ROOT As String = "The certificate or certificate chain is based on an untrusted root"
Private Const ERR_TRUST_IS_NOT_TIME_VALID As String = "The certificate has expired"
Private Const ERR_TRUST_REVOCATION_STATUS_UNKNOWN As String = "The revocation status of the certificate or one of the certificates in the certificate chain is unknown"
Private Const ERR_UNKNOWN_CNG_MAGIC As String = "Unknown CNG private key magic (%1)"
Private Const ERR_UNKNOWN_CAPI_MAGIC As String = "Unknown CAPI private key magic (%1)"
Private Const ERR_UNKNOWN_CERTIFICATECHAIN_ERROR_MASK As String = "Unknown CertGetCertificateChain error mask (%1)"
Private WithEvents m_oSocket As cAsyncSocket
Attribute m_oSocket.VB_VarHelpID = -1
Private m_bUseTls As Boolean
Private m_bIsServer As Boolean
Private m_sRemoteHostName As String
Private m_eLocalFeatures As UcsTlsLocalFeaturesEnum
Private m_uCtx As UcsTlsContext
Private m_hRootStore As Long
Private m_oRootCa As cTlsSocket
Private m_sAlpnProtocols As String
Private m_lSendActual As Long
Private m_lSendBytes As Long
Private m_lLastSendBytes As Long
Private m_baRecvBuffer() As Byte
Private m_lRecvPos As Long
Private m_baSendBuffer() As Byte
Private m_lSendPos As Long
#If Not ImplUseShared Then
Private Enum UcsOsVersionEnum
ucsOsvNt4 = 400
ucsOsvWin98 = 410
ucsOsvWin2000 = 500
ucsOsvXp = 501
ucsOsvVista = 600
ucsOsvWin7 = 601
ucsOsvWin8 = 602
[ucsOsvWin8.1] = 603
ucsOsvWin10 = 1000
End Enum
#End If
'=========================================================================
' Error handling
'=========================================================================
Private Sub PrintError(sFunction As String)
#If ImplUseDebugLog Then
DebugLog MODULE_NAME, sFunction & "(" & Erl & ")", Err.Description & " &H" & Hex$(Err.Number), vbLogEventTypeError
#Else
Debug.Print "Critical error: " & Err.Description & " [" & MODULE_NAME & "." & sFunction & "]"
#End If
End Sub
'=========================================================================
' Properties
'=========================================================================
Public Property Get Socket() As cAsyncSocket
Set Socket = m_oSocket
End Property
Public Property Get SocketHandle() As Long
SocketHandle = m_oSocket.SocketHandle
End Property
Public Property Get LastError() As VBA.ErrObject
Dim lErrNumber As Long
Dim sErrSource As String
Set LastError = Err
With LastError
.Description = TlsGetLastError(m_uCtx, lErrNumber, sErrSource)
If LenB(.Description) <> 0 And lErrNumber <> 0 Then
.Number = lErrNumber
.Source = sErrSource
ElseIf m_oSocket.LastError <> 0 And Not m_oSocket.HasPendingEvent Then
.Description = m_oSocket.GetErrorDescription(m_oSocket.LastError)
.Number = m_oSocket.LastError
.Source = "cAsyncSocket"
Else
.Number = 0
.Source = sErrSource
End If
End With
End Property
Private Function pvSetLastError(sError As String, sErrSource As String)
m_uCtx.LastErrNumber = vbObjectError
m_uCtx.LastError = sError
m_uCtx.LastErrSource = sErrSource
End Function
Public Property Get IsClosed() As Boolean
If m_bUseTls Then
IsClosed = TlsIsClosed(m_uCtx)
Else
IsClosed = (m_oSocket.SocketHandle = INVALID_SOCKET)
End If
End Property
Public Property Get AvailableBytes() As Long
If m_bUseTls Then
AvailableBytes = m_lRecvPos
Else
AvailableBytes = m_oSocket.AvailableBytes
End If
End Property
Public Property Get LastSendBytes() As Long
If m_bUseTls Then
LastSendBytes = m_lLastSendBytes
Else
LastSendBytes = m_oSocket.LastSendBytes
End If
End Property
Public Property Get HasPendingEvent() As Boolean
HasPendingEvent = m_oSocket.HasPendingEvent
End Property
Public Property Get IsServer() As Boolean
IsServer = m_bIsServer
End Property
Public Property Get RemoteHostName() As String
RemoteHostName = m_sRemoteHostName
End Property
Public Property Get LocalFeatures() As UcsTlsLocalFeaturesEnum
LocalFeatures = m_eLocalFeatures
End Property
Public Property Get LocalCertificates() As Collection
Set LocalCertificates = m_uCtx.LocalCertificates
End Property
Public Property Set LocalCertificates(oValue As Collection)
Set m_uCtx.LocalCertificates = oValue
End Property
Public Property Get LocalPrivateKey() As Collection
Set LocalPrivateKey = m_uCtx.LocalPrivateKey
End Property
Public Property Set LocalPrivateKey(oValue As Collection)
Set m_uCtx.LocalPrivateKey = oValue
End Property
Public Property Get RemoteCertificates() As Collection
Set RemoteCertificates = m_uCtx.RemoteCertificates
End Property
Public Property Get AlpnNegotiated() As String
AlpnNegotiated = m_uCtx.AlpnNegotiated
End Property
Public Property Get SniRequested() As String
SniRequested = m_uCtx.SniRequested
End Property
Friend Property Get frRootStore() As Long
If Not m_oRootCa Is Nothing Then
frRootStore = m_oRootCa.frRootStore
Else
frRootStore = m_hRootStore
End If
End Property
'=========================================================================
' Methods
'=========================================================================
Public Function InitServerTls( _
Optional PemFiles As String, _
Optional PfxFile As String, _
Optional Password As String, _
Optional Certificates As Collection, _
Optional PrivateKey As Collection, _
Optional AlpnProtocols As String, _
Optional ByVal LocalFeatures As UcsTlsLocalFeaturesEnum) As Boolean
Dim cCerts As Collection
Dim cPrivKey As Collection
If m_bUseTls Then
GoTo QH
End If
If pvCollectionCount(Certificates) > 0 And pvCollectionCount(PrivateKey) > 0 Then
Set cCerts = Certificates
Set cPrivKey = PrivateKey
GoTo StartTls
End If
If LenB(PemFiles) <> 0 Then
If pvPkiPemImportCertificates(Split(PemFiles, "|"), cCerts, cPrivKey) Then
GoTo StartTls
End If
End If
If LenB(PfxFile) <> 0 Then
If pvPkiPkcs12ImportCertificates(PfxFile, Password, cCerts, cPrivKey) Then
GoTo StartTls
End If
End If
If Not pvPkiGenerSelfSignedCertificate(cCerts, cPrivKey) Then
GoTo QH
End If
StartTls:
m_bUseTls = True
m_bIsServer = True
m_oSocket.GetPeerName m_sRemoteHostName, 0
m_sAlpnProtocols = AlpnProtocols
If (LocalFeatures And ucsTlsSupportAll) = 0 Then
m_eLocalFeatures = LocalFeatures Or ucsTlsSupportAll
Else
m_eLocalFeatures = LocalFeatures
End If
If Not TlsInitServer(m_uCtx, m_sRemoteHostName, cCerts, cPrivKey, m_sAlpnProtocols, m_eLocalFeatures) Then
GoTo QH
End If
'--- success
InitServerTls = True
QH:
End Function
Public Function Accept( _
ConnectedSocket As cTlsSocket, _
Optional SocketAddress As String, _
Optional SocketPort As Long, _
Optional ByVal UseTls As Boolean = True) As Boolean
Const FUNC_NAME As String = "Accept"
On Error GoTo EH
If ConnectedSocket Is Nothing Then
Set ConnectedSocket = New cTlsSocket
End If
If Not m_oSocket.Accept(ConnectedSocket.Socket, SocketAddress, SocketPort) Then
GoTo QH
End If
If UseTls Then
If Not ConnectedSocket.InitServerTls(Certificates:=LocalCertificates, PrivateKey:=LocalPrivateKey, AlpnProtocols:=m_sAlpnProtocols, LocalFeatures:=m_eLocalFeatures) Then
GoTo QH
End If
End If
'--- success
Accept = True
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function Connect( _
HostAddress As String, _
ByVal HostPort As Long, _
Optional ByVal UseTls As Boolean = True, _
Optional ByVal LocalFeatures As UcsTlsLocalFeaturesEnum, _
Optional RootCa As cTlsSocket, _
Optional AlpnProtocols As String) As Boolean
Const FUNC_NAME As String = "Connect"
On Error GoTo EH
m_bUseTls = UseTls
m_sRemoteHostName = HostAddress
m_eLocalFeatures = LocalFeatures
Set m_oRootCa = RootCa
m_sAlpnProtocols = AlpnProtocols
If Not m_oSocket.Connect(HostAddress, HostPort) Then
GoTo QH
End If
'-- success
Connect = True
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function StartTls( _
Optional RemoteHostName As String, _
Optional ByVal LocalFeatures As UcsTlsLocalFeaturesEnum, _
Optional RootCa As cTlsSocket, _
Optional AlpnProtocols As String) As Boolean
Const FUNC_NAME As String = "StartTls"
Dim bResult As Boolean
Dim baEmpty() As Byte
Dim cCerts As Collection
Dim cPrivKey As Collection
On Error GoTo EH
If TlsIsStarted(m_uCtx) Then
GoTo QH
End If
m_bUseTls = True
m_bIsServer = False
If LenB(RemoteHostName) <> 0 Then
m_sRemoteHostName = RemoteHostName
End If
If (LocalFeatures And ucsTlsSupportAll) = 0 Then
m_eLocalFeatures = LocalFeatures Or ucsTlsSupportAll Or IIf(OsVersion < ucsOsvXp, ucsTlsIgnoreServerCertificateErrors Or ucsTlsIgnoreServerCertificateRevocation, 0)
Else
m_eLocalFeatures = LocalFeatures
End If
If Not RootCa Is Nothing Then
Set m_oRootCa = RootCa
If m_hRootStore <> 0 Then
Call CertCloseStore(m_hRootStore, 0)
m_hRootStore = 0
End If
End If
If LenB(AlpnProtocols) <> 0 Then
m_sAlpnProtocols = AlpnProtocols
End If
Set cCerts = LocalCertificates
Set cPrivKey = LocalPrivateKey
If Not TlsInitClient(m_uCtx, m_sRemoteHostName, m_eLocalFeatures, Me, m_sAlpnProtocols) Then
GoTo QH
End If
Set LocalCertificates = cCerts
Set LocalPrivateKey = cPrivKey
bResult = TlsHandshake(m_uCtx, baEmpty, 0, m_baSendBuffer, m_lSendPos)
If Not pvOnSend() Then
GoTo QH
End If
If Not bResult Then
GoTo QH
End If
'--- success
StartTls = True
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function ReceiveText( _
Optional HostAddress As String = STR_CHR1, _
Optional HostPort As Long, _
Optional ByVal CodePage As UcsAsyncSocketCodePageEnum = ucsScpUtf8) As String
Const FUNC_NAME As String = "ReceiveText"
Dim baBuffer() As Byte
On Error GoTo EH
If m_bUseTls Then
If ReceiveArray(baBuffer) Then
ReceiveText = m_oSocket.FromTextArray(baBuffer, CodePage)
End If
Else
ReceiveText = m_oSocket.ReceiveText(HostAddress, HostPort, CodePage)
End If
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function ReceiveArray( _
Buffer() As Byte, _
Optional HostAddress As String = STR_CHR1, _
Optional HostPort As Long) As Boolean
Const FUNC_NAME As String = "ReceiveArray"
On Error GoTo EH
If m_bUseTls Then
If m_lRecvPos = 0 Then
If TlsIsClosed(m_uCtx) Then
GoTo QH
End If
If Not pvOnReceive() Then
GoTo QH
End If
End If
If m_lRecvPos > 0 Then
Buffer = m_baRecvBuffer
Erase m_baRecvBuffer
m_lRecvPos = 0
Else
Buffer = vbNullString
End If
'--- success
ReceiveArray = True
Else
ReceiveArray = m_oSocket.ReceiveArray(Buffer, HostAddress, HostPort)
End If
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function SendText( _
Text As String, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long, _
Optional ByVal CodePage As UcsAsyncSocketCodePageEnum = ucsScpUtf8) As Boolean
Const FUNC_NAME As String = "SendText"
On Error GoTo EH
If m_bUseTls Then
SendText = SendArray(m_oSocket.ToTextArray(Text, CodePage), HostAddress, HostPort)
Else
SendText = m_oSocket.SendText(Text, HostAddress, HostPort, CodePage)
End If
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function SendArray( _
Buffer() As Byte, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long) As Boolean
Const FUNC_NAME As String = "SendArray"
Dim lInputSize As Long
On Error GoTo EH
If m_bUseTls Then
If TlsIsClosed(m_uCtx) Then
GoTo QH
End If
lInputSize = pvArraySize(Buffer)
m_lSendBytes = m_lSendBytes + lInputSize
If Not TlsSend(m_uCtx, Buffer, lInputSize, m_baSendBuffer, m_lSendPos) Then
RaiseEvent OnError(LastError.Number, ucsSfdWrite)
GoTo QH
End If
If TlsIsReady(m_uCtx) Then
If Not pvOnSend() Then
GoTo QH
End If
End If
'--- success
SendArray = True
Else
SendArray = m_oSocket.SendArray(Buffer, HostAddress, HostPort)
End If
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function Send( _
ByVal BufPtr As Long, _
ByVal BufLen As Long, _
Optional HostAddress As String, _
Optional ByVal HostPort As Long) As Long
Const FUNC_NAME As String = "Send"
Dim baBuffer() As Byte
On Error GoTo EH
If BufLen = 0 Then
'--- do nothing
ElseIf m_bUseTls Then
pvWriteBuffer baBuffer, 0, BufPtr, BufLen
If Not SendArray(baBuffer) Then
Send = -1
Else
Send = BufLen
End If
Else
Send = m_oSocket.Send(BufPtr, BufLen, HostAddress, HostPort)
End If
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function ShutDown() As Boolean
Const FUNC_NAME As String = "ShutDown"
On Error GoTo EH
If m_bUseTls Then
If TlsIsReady(m_uCtx) And Not TlsIsShutdown(m_uCtx) Then
If Not pvOnShutdown() Then
GoTo QH
End If
End If
'--- success
ShutDown = True
Else
ShutDown = m_oSocket.ShutDown
End If
QH:
Exit Function
EH:
PrintError FUNC_NAME
Resume QH
End Function
Public Function GetErrorDescription(ByVal ErrorCode As Long) As String
If ErrorCode = vbObjectError Then
GetErrorDescription = TlsGetLastError(m_uCtx)
Else
GetErrorDescription = m_oSocket.GetErrorDescription(ErrorCode)
End If
End Function
Public Sub Close_()
If m_bUseTls Then
If TlsIsReady(m_uCtx) And Not TlsIsShutdown(m_uCtx) Then
If Not pvOnShutdown() Then
GoTo QH
End If
End If
Else
m_oSocket.Close_
End If
QH:
End Sub
Public Sub PostEvent(ByVal EventMask As UcsAsyncSocketEventMaskEnum, Optional ByVal Immediate As Boolean)
If Immediate Then
Select Case EventMask
Case ucsSfdRead
RaiseEvent OnReceive
Case ucsSfdWrite
RaiseEvent OnSend
Case ucsSfdConnect
RaiseEvent OnConnect
Case ucsSfdAccept
RaiseEvent OnAccept
Case ucsSfdClose
RaiseEvent OnClose
TlsTerminate m_uCtx
End Select
RaiseEvent AfterNotify(EventMask)
If EventMask = ucsSfdRead And AvailableBytes = 0 Then
m_oSocket.Receive 0, 0 '--- enable FD_READ notification
End If
Else
m_oSocket.PostEvent EventMask, Immediate
End If
End Sub
'= forwarded =============================================================
Public Function Create( _
Optional ByVal SocketPort As Long, _
Optional ByVal SocketType As UcsAsyncSocketTypeEnum = ucsSckStream, _
Optional ByVal EventMask As UcsAsyncSocketEventMaskEnum = ucsSfdAll, _
Optional SocketAddress As String) As Boolean
Create = m_oSocket.Create(SocketPort, SocketType, EventMask, SocketAddress)
End Function
Public Function Listen(Optional ByVal ConnectionBacklog As Long = 5) As Boolean
Listen = m_oSocket.Listen(ConnectionBacklog)
End Function
Public Function GetSockName(SocketAddress As String, SocketPort As Long) As Boolean
GetSockName = m_oSocket.GetSockName(SocketAddress, SocketPort)
End Function
Public Function GetPeerName(PeerAddress As String, PeerPort As Long) As Boolean
GetPeerName = m_oSocket.GetPeerName(PeerAddress, PeerPort)
End Function
Public Function GetLocalHost(HostName As String, HostAddress As String) As Boolean
GetLocalHost = m_oSocket.GetLocalHost(HostName, HostAddress)
End Function
Public Function Attach( _
ByVal SocketHandle As Long, _
Optional ByVal EventMask As UcsAsyncSocketEventMaskEnum = ucsSfdAll) As Boolean
Attach = m_oSocket.Attach(SocketHandle, EventMask)
End Function
Public Function Detach() As Long
Detach = m_oSocket.Detach()
End Function
Public Function Bind(Optional SocketAddress As String, Optional ByVal SocketPort As Long) As Boolean
Bind = m_oSocket.Bind(SocketAddress, SocketPort)
End Function
Public Function FromTextArray(baText() As Byte, Optional ByVal CodePage As UcsAsyncSocketCodePageEnum = ucsScpUtf8) As String
FromTextArray = m_oSocket.FromTextArray(baText, CodePage)
End Function
Public Function ToTextArray(sText As String, Optional ByVal CodePage As UcsAsyncSocketCodePageEnum = ucsScpUtf8) As Byte()
ToTextArray = m_oSocket.ToTextArray(sText, CodePage)
End Function
'= sync ==================================================================
#If ImplSync Then
Public Function SyncConnect( _
HostAddress As String, _
ByVal HostPort As Long, _
Optional ByVal Timeout As Long, _
Optional ByVal UseTls As Boolean = True, _
Optional ByVal LocalFeatures As UcsTlsLocalFeaturesEnum, _
Optional RootCa As cTlsSocket, _
Optional AlpnProtocols As String) As Boolean
Const FUNC_NAME As String = "SyncConnect"
On Error GoTo EH
If UseTls Then
If Timeout = 0 Then
Timeout = DEF_TIMEOUT
End If
If Not Connect(HostAddress, HostPort, UseTls:=UseTls, LocalFeatures:=LocalFeatures, RootCa:=RootCa, AlpnProtocols:=AlpnProtocols) Then
GoTo QH
End If
If Not SyncWaitForEvent(Timeout, ucsSfdConnect) Then
GoTo QH
End If
'--- success
SyncConnect = True
Else
SyncConnect = m_oSocket.SyncConnect(HostAddress, HostPort, Timeout:=Timeout)
End If
QH:
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function SyncSendText( _
Text As String, _
Optional ByVal Timeout As Long, _
Optional ByVal CodePage As UcsAsyncSocketCodePageEnum = ucsScpUtf8) As Boolean
Const FUNC_NAME As String = "SyncSendText"
On Error GoTo EH
SyncSendText = SyncSendArray(m_oSocket.ToTextArray(Text, CodePage), Timeout:=Timeout)
Exit Function
EH:
PrintError FUNC_NAME
End Function
Public Function SyncSendArray(Buffer() As Byte, Optional ByVal Timeout As Long) As Boolean
Const FUNC_NAME As String = "SyncSendArray"
On Error GoTo EH
If UBound(Buffer) < 0 Then
SyncSendArray = True
ElseIf m_bUseTls Then
If Timeout = 0 Then
Timeout = DEF_TIMEOUT
End If
If Not SendArray(Buffer) Then