📄 ssl_cli.c
字号:
"Invalid supplemental data" ) );
}
}
/* Process the optional server cert chain:
byte ID = SSL_HAND_CERTIFICATE
uint24 len
uint24 certLen | 1...n certs ordered
byte[] cert | leaf -> root */
if( handshakeInfo->authAlgo != CRYPT_ALGO_NONE )
{
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
status = readSSLCertChain( sessionInfoPtr, handshakeInfo,
stream, &sessionInfoPtr->iKeyexCryptContext,
FALSE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
/* Process the optional server keyex:
byte ID = SSL_HAND_SERVER_KEYEXCHANGE
uint24 len
uint16 dh_pLen
byte[] dh_p
uint16 dh_gLen
byte[] dh_g
uint16 dh_YsLen
byte[] dh_Ys
uint16 signatureLen
byte[] signature */
if( isKeyxAlgo( handshakeInfo->keyexAlgo ) )
{
KEYAGREE_PARAMS keyAgreeParams;
void *keyData = DUMMY_INIT_PTR;
int keyDataOffset, keyDataLength = DUMMY_INIT, dummy;
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
SSL_HAND_SERVER_KEYEXCHANGE,
UINT16_SIZE + MIN_PKCSIZE + \
UINT16_SIZE + 1 + \
UINT16_SIZE + MIN_PKCSIZE + \
UINT16_SIZE + MIN_PKCSIZE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
/* Read the server DH key and DH public value */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
keyDataOffset = stell( stream );
status = readInteger16UChecked( stream, NULL, &dummy,
MIN_PKCSIZE, CRYPT_MAX_PKCSIZE );
if( cryptStatusOK( status ) )
status = readInteger16U( stream, NULL, &dummy,
1, CRYPT_MAX_PKCSIZE );
if( cryptStatusOK( status ) )
status = initDHcontextSSL( &handshakeInfo->dhContext, keyData,
stell( stream ) - keyDataOffset,
CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = readInteger16UChecked( stream,
keyAgreeParams.publicValue,
&keyAgreeParams.publicValueLen,
MIN_PKCSIZE, CRYPT_MAX_PKCSIZE );
if( cryptStatusOK( status ) )
{
keyDataLength = stell( stream ) - keyDataOffset;
status = sMemGetDataBlockAbs( stream, keyDataOffset, &keyData,
keyDataLength );
}
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
/* Some misconfigured servers may use very short keys, we
perform a special-case check for these and return a more
specific message than the generic bad-data */
if( status == CRYPT_ERROR_NOSECURE )
{
retExt( CRYPT_ERROR_NOSECURE,
( CRYPT_ERROR_NOSECURE, SESSION_ERRINFO,
"Insecure key used in key exchange" ) );
}
retExt( cryptArgError( status ) ? \
CRYPT_ERROR_BADDATA : status,
( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status,
SESSION_ERRINFO,
"Invalid server key agreement parameters" ) );
}
/* Check the server's signature on the DH parameters */
status = checkKeyexSignature( sessionInfoPtr, handshakeInfo,
stream, keyData, keyDataLength );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
retExt( status,
( status, SESSION_ERRINFO,
"Bad server key agreement parameter signature" ) );
}
/* Perform phase 2 of the DH key agreement */
status = krnlSendMessage( handshakeInfo->dhContext,
IMESSAGE_CTX_DECRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
{
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
sMemDisconnect( stream );
return( status );
}
memcpy( handshakeInfo->premasterSecret, keyAgreeParams.wrappedKey,
keyAgreeParams.wrappedKeyLen );
handshakeInfo->premasterSecretSize = keyAgreeParams.wrappedKeyLen;
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
}
/* Process the optional server cert request:
byte ID = SSL_HAND_SERVER_CERTREQUEST
uint24 len
byte certTypeLen
byte[] certType
uint16 caNameListLen
uint16 caNameLen
byte[] caName
We don't really care what's in the cert request packet since the
contents are irrelevant, in a number of cases servers have been
known to send out superfluous cert requests without the admins even
knowning that they're doing it. In other cases servers send out
requests for every CA they know of (150-160 CAs), which is pretty
much meaningless since they can't possibly trust all of those CAs
to authorise access to their site. Because of this, all we do here
is perform a basic sanity check and remember that we may need to
submit a cert later on.
Since we're about to peek ahead into the stream to see if we need to
process a server cert request, we have to refresh the stream at this
point in case the cert request wasn't bundled with the preceding
packets */
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
if( sPeek( stream ) == SSL_HAND_SERVER_CERTREQUEST )
{
/* Although the spec says that at least one CA name entry must be
present, some implementations send a zero-length list, so we
allow this as well. The spec was changed in late TLS 1.1 drafts
to reflect this practice */
status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
SSL_HAND_SERVER_CERTREQUEST,
1 + 1 + UINT16_SIZE );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
length = sgetc( stream );
if( cryptStatusError( length ) || \
length < 1 || cryptStatusError( sSkip( stream, length ) ) )
{
sMemDisconnect( stream );
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid cert request certificate type" ) );
}
length = readUint16( stream );
if( cryptStatusError( length ) || \
( length > 0 && cryptStatusError( sSkip( stream, length ) ) ) )
{
sMemDisconnect( stream );
retExt( CRYPT_ERROR_BADDATA,
( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
"Invalid cert request CA name list" ) );
}
needClientCert = TRUE;
}
/* Process the server hello done:
byte ID = SSL_HAND_SERVER_HELLODONE
uint24 len = 0 */
status = refreshHSStream( sessionInfoPtr, handshakeInfo );
if( cryptStatusError( status ) )
return( status );
status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
SSL_HAND_SERVER_HELLODONE, 0 );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
/* If we need a client cert, build the client cert packet */
status = openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
SSL_MSG_HANDSHAKE );
if( cryptStatusError( status ) )
return( status );
if( needClientCert )
{
BOOLEAN sentResponse = FALSE;
/* If we haven't got a cert available, tell the server. SSL and TLS
differ here, SSL sends a no-certificate alert while TLS sends an
empty client cert packet, which is handled further on */
if( sessionInfoPtr->privateKey == CRYPT_ERROR )
{
setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PRIVATEKEY,
CRYPT_ERRTYPE_ATTR_ABSENT );
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
static const BYTE FAR_BSS noCertAlertSSLTemplate[] = {
SSL_MSG_ALERT, /* ID */
SSL_MAJOR_VERSION, SSL_MINOR_VERSION_SSL,/* Version */
0, 2, /* Length */
SSL_ALERTLEVEL_WARNING, SSL_ALERT_NO_CERTIFICATE
};
/* This is an alert-protocol message rather than a handshake
message, so we don't add it to the handshake packet stream
but write it directly to the network stream */
swrite( &sessionInfoPtr->stream, noCertAlertSSLTemplate, 7 );
sentResponse = TRUE;
}
/* The reaction to the lack of a cert is up to the server (some
just request one anyway even though they can't do anything
with it), so from here on we just continue as if nothing had
happened */
needClientCert = FALSE;
}
/* If we haven't sent a response yet, send it now */
if( !sentResponse )
{
status = writeSSLCertChain( sessionInfoPtr, stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
}
/* Build the client key exchange packet:
byte ID = SSL_HAND_CLIENT_KEYEXCHANGE
uint24 len
DH:
uint16 yLen
byte[] y
PSK:
uint16 userIDLen
byte[] userID
RSA:
[ uint16 encKeyLen - TLS only ]
byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random ) */
packetOffset = continueHSPacketStream( stream,
SSL_HAND_CLIENT_KEYEXCHANGE );
if( isKeyxAlgo( handshakeInfo->keyexAlgo ) )
{
KEYAGREE_PARAMS keyAgreeParams;
/* Perform phase 1 of the DH key agreement process */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
status = krnlSendMessage( handshakeInfo->dhContext,
IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusError( status ) )
{
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
sMemDisconnect( stream );
return( status );
}
writeInteger16U( stream, keyAgreeParams.publicValue,
keyAgreeParams.publicValueLen );
zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
}
else
{
if( handshakeInfo->authAlgo == CRYPT_ALGO_NONE )
{
const ATTRIBUTE_LIST *attributeListPtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_PASSWORD );
/* Create the shared premaster secret from the user password */
status = createSharedPremasterSecret( \
handshakeInfo->premasterSecret,
CRYPT_MAX_PKCSIZE + CRYPT_MAX_TEXTSIZE,
&handshakeInfo->premasterSecretSize,
attributeListPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, SESSION_ERRINFO,
"Couldn't create SSL master secret from shared "
"secret/password value" ) );
}
/* Write the PSK client identity */
attributeListPtr = \
findSessionInfo( sessionInfoPtr->attributeList,
CRYPT_SESSINFO_USERNAME );
writeUint16( stream, attributeListPtr->valueLength );
swrite( stream, attributeListPtr->value,
attributeListPtr->valueLength );
}
else
{
BYTE wrappedKey[ CRYPT_MAX_PKCSIZE + 8 ];
int wrappedKeyLength;
status = wrapPremasterSecret( sessionInfoPtr, handshakeInfo,
wrappedKey, CRYPT_MAX_PKCSIZE,
&wrappedKeyLength );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
{
/* The original Netscape SSL implementation didn't provide a
length for the encrypted key and everyone copied that so
it became the de facto standard way to do it (Sic faciunt
omnes. The spec itself is ambiguous on the topic). This
was fixed in TLS (although the spec is still ambiguous) so
the encoding differs slightly between SSL and TLS */
swrite( stream, wrappedKey, wrappedKeyLength );
}
else
writeInteger16U( stream, wrappedKey, wrappedKeyLength );
}
}
status = completeHSPacketStream( stream, packetOffset );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
/* If we need to supply a client cert, send the signature generated with
the cert to prove possession of the private key */
if( needClientCert )
{
/* Write the packet header and drop in the signature data */
packetOffset = continueHSPacketStream( stream,
SSL_HAND_CLIENT_CERTVERIFY );
status = createCertVerify( sessionInfoPtr, handshakeInfo, stream );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
status = completeHSPacketStream( stream, packetOffset );
if( cryptStatusError( status ) )
{
sMemDisconnect( stream );
return( status );
}
}
/* Wrap and MAC the packet. This is followed by the change cipherspec
packet so we don't send it at this point but leave it to be sent by
the shared handshake-completion code */
status = completePacketStreamSSL( stream, 0 );
if( cryptStatusOK( status ) )
status = dualMacDataWrite( handshakeInfo, stream );
return( status );
}
/****************************************************************************
* *
* Session Access Routines *
* *
****************************************************************************/
void initSSLclientProcessing( SSL_HANDSHAKE_INFO *handshakeInfo )
{
handshakeInfo->beginHandshake = beginClientHandshake;
handshakeInfo->exchangeKeys = exchangeClientKeys;
}
#endif /* USE_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -