272 lines
12 KiB
VB.net
272 lines
12 KiB
VB.net
|
|
#Region "Microsoft.VisualBasic::a9d3b4643cdebfd30e5c7ed4825f5ef4, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\SSL\Protocol.vb"
|
|||
|
|
|
|||
|
|
' Author:
|
|||
|
|
'
|
|||
|
|
' asuka (amethyst.asuka@gcmodeller.org)
|
|||
|
|
' xie (genetics@smrucc.org)
|
|||
|
|
' xieguigang (xie.guigang@live.com)
|
|||
|
|
'
|
|||
|
|
' Copyright (c) 2018 GPL3 Licensed
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
' GNU GENERAL PUBLIC LICENSE (GPL3)
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
' This program is free software: you can redistribute it and/or modify
|
|||
|
|
' it under the terms of the GNU General Public License as published by
|
|||
|
|
' the Free Software Foundation, either version 3 of the License, or
|
|||
|
|
' (at your option) any later version.
|
|||
|
|
'
|
|||
|
|
' This program is distributed in the hope that it will be useful,
|
|||
|
|
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
|
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
|
' GNU General Public License for more details.
|
|||
|
|
'
|
|||
|
|
' You should have received a copy of the GNU General Public License
|
|||
|
|
' along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
' /********************************************************************************/
|
|||
|
|
|
|||
|
|
' Summaries:
|
|||
|
|
|
|||
|
|
' Module SSLProtocols
|
|||
|
|
'
|
|||
|
|
' Function: (+3 Overloads) Handshaking
|
|||
|
|
' Interface ISSLServices
|
|||
|
|
'
|
|||
|
|
' Properties: CA, DeclaringModule, InstallCertificates, PrivateKeys, RaiseHandshakingEvent
|
|||
|
|
' RefuseHandshake, ResponseHandler
|
|||
|
|
'
|
|||
|
|
' Function: Install
|
|||
|
|
'
|
|||
|
|
' Delegate Sub
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
' Delegate Function
|
|||
|
|
'
|
|||
|
|
' Function: __sslHandshake, SSLServicesResponseHandler
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
'
|
|||
|
|
' /********************************************************************************/
|
|||
|
|
|
|||
|
|
#End Region
|
|||
|
|
|
|||
|
|
Imports System.Reflection
|
|||
|
|
Imports Microsoft.VisualBasic.Net.Http
|
|||
|
|
Imports Microsoft.VisualBasic.Net.Protocols
|
|||
|
|
Imports Microsoft.VisualBasic.Win32
|
|||
|
|
|
|||
|
|
Namespace Net.SSL
|
|||
|
|
|
|||
|
|
Public Module SSLProtocols
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
''' 客户端与服务器之间初始化加密连接
|
|||
|
|
''' </summary>
|
|||
|
|
''' <param name="CA">客户端的证书,这个是服务器来进行客户端程序的完整性验证的</param>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Public Function Handshaking(CA As SSL.Certificate, services As System.Net.IPEndPoint) As SSL.Certificate
|
|||
|
|
Dim request As RequestStream =
|
|||
|
|
New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.SSLHandshake,
|
|||
|
|
New Byte() {}) With {
|
|||
|
|
.uid = CA.uid
|
|||
|
|
}
|
|||
|
|
request = New Net.AsynInvoke(services).SendMessage(request, CA, isPublicToken:=True) '这个函数会把用户的账号和当前的客户端的数字证书发送给服务器
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
'服务器验证数字证书通过之后就会返回动态的客户端的私有密匙,一般是对随机数做MD5得到私有密匙
|
|||
|
|
Dim PrivateKey As New SSL.Certificate(request)
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(PrivateKey)} hash:={PrivateKey.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
Return PrivateKey
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
Public Function Handshaking(PublicToken As SSL.Certificate, uid As String, services As System.Net.IPEndPoint) As SSL.Certificate
|
|||
|
|
Dim CA = SSL.Certificate.CopyFrom(PublicToken, uid)
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
Dim privateKey As SSL.Certificate = Handshaking(CA, services)
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(privateKey)} hash:={privateKey.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
Return privateKey
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
Public Function Handshaking(CA As SSL.Certificate, services As System.Net.IPEndPoint, Install As InstallCertificates) As SSL.Certificate
|
|||
|
|
Dim request As RequestStream =
|
|||
|
|
New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.SSLHandshake,
|
|||
|
|
New Byte() {}) With {
|
|||
|
|
.uid = CA.uid
|
|||
|
|
}
|
|||
|
|
request = New Net.AsynInvoke(services).SendMessage(request, CA, isPublicToken:=True) '这个函数会把用户的账号和当前的客户端的数字证书发送给服务器
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
'服务器验证数字证书通过之后就会返回动态的客户端的私有密匙,一般是对随机数做MD5得到私有密匙
|
|||
|
|
Dim PrivateKey As SSL.Certificate = Install(request.GetUTF8String, CA.uid)
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(PrivateKey)} hash:={PrivateKey.uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
Return PrivateKey
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
''' 抽象SSL服务器
|
|||
|
|
''' </summary>
|
|||
|
|
Public Interface ISSLServices
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
''' 告诉SSL层如何安装数字证书
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Property InstallCertificates As InstallCertificates
|
|||
|
|
''' <summary>
|
|||
|
|
''' 有新的客户端请求进行连接
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Property RaiseHandshakingEvent As HandshakingEvent
|
|||
|
|
''' <summary>
|
|||
|
|
''' 对于某些应用出于安全性的考虑,会将这里设置为False,则服务器就会全部拒绝后面的所有的握手请求,只接受来自于从外部导入的用户证书的数据请求
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Property RefuseHandshake As Boolean
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
''' 公共密匙
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
ReadOnly Property CA As SSL.Certificate
|
|||
|
|
''' <summary>
|
|||
|
|
''' 客户端的私有密匙
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
ReadOnly Property PrivateKeys As Dictionary(Of Long, SSL.Certificate)
|
|||
|
|
''' <summary>
|
|||
|
|
''' 处理私有密匙的数据请求
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
ReadOnly Property ResponseHandler As Net.Abstract.DataRequestHandler
|
|||
|
|
ReadOnly Property DeclaringModule As Object
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
'''
|
|||
|
|
''' </summary>
|
|||
|
|
''' <param name="CA"></param>
|
|||
|
|
''' <param name="[overrides]">当证书的哈希值有冲突的时候,新安装的证书<paramref name="ca"/>可不可以将旧的证书覆盖掉</param>
|
|||
|
|
Function Install(CA As Certificate, [overrides] As Boolean, Optional trace As String = "") As Boolean
|
|||
|
|
|
|||
|
|
End Interface
|
|||
|
|
|
|||
|
|
Public Delegate Sub HandshakingEvent(uid As Long, CA As SSL.Certificate, remoteDev As System.Net.IPEndPoint)
|
|||
|
|
Public Delegate Function InstallCertificates(privateKey As String, uid As Long) As Certificate
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
'''
|
|||
|
|
''' </summary>
|
|||
|
|
''' <param name="ssl"></param>
|
|||
|
|
''' <param name="CA">解密使用的证书凭据,这个用来鉴别客户端身份是否被伪造</param>
|
|||
|
|
''' <param name="request"></param>
|
|||
|
|
''' <param name="remoteDev"></param>
|
|||
|
|
''' <param name="InstallCertificates"></param>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Public Function SSLServicesResponseHandler(ssl As ISSLServices, CA As Long,
|
|||
|
|
request As RequestStream,
|
|||
|
|
remoteDev As System.Net.IPEndPoint,
|
|||
|
|
InstallCertificates As InstallCertificates) As RequestStream
|
|||
|
|
Dim uid As Long
|
|||
|
|
|
|||
|
|
If request.IsSSL_PublicToken Then
|
|||
|
|
uid = request.uid
|
|||
|
|
request = ssl.CA.Decrypt(request)
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
If request.IsSSLHandshaking Then '客户端与服务器之间进行连接的初始化,服务器会在这里为客户端动态的生成一个密匙
|
|||
|
|
request = __sslHandshake(uid, ssl, request, remoteDev, InstallCertificates)
|
|||
|
|
Return request
|
|||
|
|
ElseIf request.IsSSLProtocol Then
|
|||
|
|
uid = request.uid
|
|||
|
|
|
|||
|
|
If Not ssl.PrivateKeys.ContainsKey(uid) Then ' 不存在的数字证书
|
|||
|
|
' 记录进系统日志
|
|||
|
|
If WindowsServices.Initialized Then
|
|||
|
|
Call ServicesLogs.WriteEntry({$"Remote socket {remoteDev.ToString} try send request with an not authorised certificates, and ssl server refused this request!",
|
|||
|
|
$"{NameOf(CA)} (not_authorised) {CA}",
|
|||
|
|
$"{NameOf(remoteDev)}: {remoteDev.ToString}"},
|
|||
|
|
$"{ssl.DeclaringModule.GetType.FullName} [{Scripting.ToString(ssl.DeclaringModule)}] ==> {MethodBase.GetCurrentMethod}",
|
|||
|
|
EventLogEntryType.Warning)
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
Return New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.InvalidCertificates,
|
|||
|
|
NameOf(RequestStream.Protocols.InvalidCertificates))
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
Dim PrivateCertificate As SSL.Certificate = ssl.PrivateKeys(uid)
|
|||
|
|
request = PrivateCertificate.Decrypt(request) '使用用户的私有密匙进行加密
|
|||
|
|
request = ssl.ResponseHandler(CA, request, remoteDev) ' CA应该是用户客户端的数字证书编号
|
|||
|
|
request = PrivateCertificate.Encrypt(request)
|
|||
|
|
Return request
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
Return NetResponse.RFC_NO_CERT
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
''' <summary>
|
|||
|
|
''' 客户端与服务器之间进行连接的初始化,服务器会在这里为客户端动态的生成一个密匙
|
|||
|
|
''' </summary>
|
|||
|
|
''' <returns></returns>
|
|||
|
|
Private Function __sslHandshake(uid As Long, ssl As ISSLServices,
|
|||
|
|
request As RequestStream,
|
|||
|
|
remoteDev As System.Net.IPEndPoint,
|
|||
|
|
InstallCertificates As InstallCertificates) As RequestStream
|
|||
|
|
If ssl.RefuseHandshake Then
|
|||
|
|
Return New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.InvalidCertificates,
|
|||
|
|
"Services Refused!")
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
Dim key As String = Guid.NewGuid.ToString
|
|||
|
|
key = SecurityString.MD5Hash.GetMd5Hash(key)
|
|||
|
|
|
|||
|
|
If uid <> request.uid Then
|
|||
|
|
Return New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.InvalidCertificates,
|
|||
|
|
NameOf(RequestStream.Protocols.InvalidCertificates))
|
|||
|
|
Else
|
|||
|
|
request = New RequestStream(RequestStream.SYS_PROTOCOL,
|
|||
|
|
RequestStream.Protocols.SSLHandshake, key) With {
|
|||
|
|
.uid = uid
|
|||
|
|
}
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
If ssl.PrivateKeys.ContainsKey(uid) Then ' 哈希函数设计不正确,有重复的哈希值,则当前的握手用户不能够使用这个哈希值,需要重新握手
|
|||
|
|
Call $"{NameOf(SSLServicesResponseHandler)} ==> {uid} was duplicated!".__DEBUG_ECHO
|
|||
|
|
Return New RequestStream(RequestStream.SYS_PROTOCOL, RequestStream.Protocols.InvalidCertificates, "Duplicated hash value!")
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
#If DEBUG Then
|
|||
|
|
Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking hash:={uid}".__DEBUG_ECHO
|
|||
|
|
#End If
|
|||
|
|
|
|||
|
|
Dim PrivateKey As SSL.Certificate = InstallCertificates(key, uid)
|
|||
|
|
Call ssl.PrivateKeys.Add(uid, PrivateKey)
|
|||
|
|
Call ssl.RaiseHandshakingEvent()(uid, PrivateKey, remoteDev)
|
|||
|
|
|
|||
|
|
request = Net.SSL.Certificate.CopyFrom(ssl.CA, uid).Encrypt(request)
|
|||
|
|
|
|||
|
|
Return request
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
End Module
|
|||
|
|
End Namespace
|