microsoft-visualbasic-runtime/ApplicationServices/Tools/Network/SSL/Protocol.vb

272 lines
12 KiB
VB.net
Raw Normal View History

2018-08-02 20:14:48 +08:00
#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