Certificate Validation
The examples in this section rely on sample
security files included with VA Smalltalk.
Security Files
These are shipped with version 12.0.1 in the <varoot>/samples/ssl directory.
•ssl/vast_ca.pem
•ssl/vast_client.pem
•ssl/vast_client_key.pem
•ssl/vast_server.pem
•ssl/vast_server_key.pem
vast_ca.pem is the certificate authorization file. The certificates are found in vast_client.pem and vast_ server.pem. Each certificate contains a public key. The private keys are found in vast_client_key.pem and vast_server _key.pem.
HTTPS server certificate validation by an HTTPS client
Typically, security policies indicate that an HTTPS client should validate the X509 certificate presented by an HTTPS server, and should verify that the identity asserted by a validated certificate is in fact the identity of the intended server.
Beginning with Version 6.0.2 includes enhancements to the SST HTTPS client which enable applications to specify via the security configuration for an HTTPS client transport that a strict certificate validation policy should be applied. In addition, an SstHttpClient can be configured with a @requiredPeerName that will result in the client auto-verifying the identity asserted by the server credential.
To enable strict certificate validation, the HTTPS client transport security configuration must specify:
1. @caFile - the file name of a trusted certificate authority (CA) certificate store, and
2. @verify - the validation policy, and
3. @verifyDepth - the maximum depth of the presented certificate chain.
The @verify parameter must be set to "SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT".
Unless known to be too limiting, a reasonable default value for @verifyDepth is the Integer '2'.
The @caFile is a certificate store in PEM format, as per OpenSSL.
Example 1. The code below configures the default HTTPS client transport for strict server certificate validation.
(SstTransport configurationRegistry at: 'httpsl')
securityConfiguration: (SciSslSocketConfiguration new
sslVersion: 'TLS';
caFile: 'certs/sst_ca.pem';
verify: SciSslConstants::SSL_VERIFY_PEER | SciSslConstants::SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
verifyDepth: 2;
yourself).
With this configuration in place, the fetch below will fall into the exception handler if the presented server certificate cannot be validated against the trusted CA certificate store.
['https://www.acme.com/secure/index.html' sstAsUrl fetch]
when: SstConstants::ExSstNonFatalError
do: [:sig| sig exitWith: ('SSL handshake failed:*' match: sig arguments last errorObject)].
Example 2. To enable server identity verification, in addition to certificate validation, SstHttpsConnection now has a "getter" for @peerCredential, allowing an application to test the Subject attribute of the server's X509 certificate. Auto-verification is enabled in SstHttpClient via a new @requiredPeerName attribute. If this attribute is set, the client will test the certificate Subject immediately after successful SSL connection negotiation (prior to sending the HTTP request) and generate an exception if the Subject does not match the specified @requiredPeerName.
|client response|
(client := SstHttpClient forTransportScheme: 'httpsl') startUp.
client requiredPeerName: '/who/do'.
['https://www.acme.com/secure/index.html' sstAsUrl fetch] ensure: [client shutDown]]
when: SstConstants::ExSstNonFatalError
do: [:sig| sig exitWith: ('Invalid peer:*' match: sig arguments last errorObject)].
Two-Way Authentication – The Client is Required to Present a Certificate to the Server
VA Smalltalk supports two-way authentication; both client and server can be configured to send a certificate and authenticate. The workspaces below illustrate how to configure a server to require the client to present a certificate and a client example which presents a certificate.
You may copy these workspaces into an image which has the feature ST: TCP Communications loaded. Execute the server workspace first, then the client. Output appears in the System Transcript. The examples use Windows style path separators.
Server Workspace
Make sure that the
security files vast_server.pem, vast_server_key.pem and vast_ca.pem are in the directory in which the Smalltalk image is started or change <dir> to the directory in which the files reside.
"Ssl Two-Way Authentication Server Workspace -- execute the code in this workspace first"
[ | config anSciSocketAddress listenSocket secureSocket rv msg path |
"Change the path variable to the location of the PEM files."
path := '<dir>'.
config := SciSslSocketConfiguration new
certificateFilename: path,'vast_server.pem';
privateKeyFilename: path,'vast_server_key.pem';
verify: SciSslConstants::SSL_VERIFY_PEER | SciSslConstants::SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
verifyDepth: 1;
caFile: path, 'vast_ca.pem';
sslVersion: 'TLS';
yourself.
anSciSocketAddress := (SciSocketAddress new)
address: SciSocketConstants::INADDRANY;
port: 2222.
listenSocket := SciSslSocket newStreamSocket.
(rv := listenSocket bind: anSciSocketAddress) isSciError
ifTrue: [ self halt ].
(rv := listenSocket listen: 5) isSciError
ifTrue: [ self halt ].
(secureSocket := listenSocket accept) isSciError
ifTrue: [ self halt ].
listenSocket close.
(rv := secureSocket sslInitialize: config) isSslError
ifTrue: [ secureSocket close. self halt ].
(rv := secureSocket sslAccept) isSslError
ifTrue: [ secureSocket close. self halt ].
(rv := secureSocket sslVerifyCertificate) ~= 0
ifTrue: [ rv halt ].
self halt. " step through and you can retrieve the certificate and get the subject name"
(rv := secureSocket sslGetPeerCertificate) isSslError
ifTrue: [ rv halt ].
(rv := rv subject oneLine) isSslError
ifTrue: [ rv halt ].
msg := ByteArray new: 4096.
(rv := secureSocket recv: msg length: 4096 startingAt: 1 flags: 0) isSslError
ifTrue: [ self halt ].
Transcript cr; nextPutAll: 'SslServer Got: ', msg asString.
((rv := secureSocket send: 'I hear you.' abrAsPSZ length: 11 startingAt: 1 flags: 0) isSslError
ifTrue: [ self halt ].
secureSocket close. ] fork
Client Workspace
Make sure that the
security files vast_ client.pem, vast_ client _key.pem and vast_ca.pem are in the directory in which the Smalltalk image is started or change <dir> to the directory in which the files reside.
"SSL Two-Way Authentication Client Workspace -- execute the code in this workspace second"
[ | config rv anSciSocketAddress secureSocket msg path |
"Change the path variable to the location of the PEM files."
path := '<dir>'.
config := SciSslSocketConfiguration new
certificateFilename: path,'vast_client.pem';
privateKeyFilename: path,'vast_client_key.pem';
verify: SciSslConstants::SSL_VERIFY_PEER ;
verifyDepth: 1;
caFile: path,'vast_ca.pem';
sslVersion: SciSslConstants::SSLv23;
yourself.
anSciSocketAddress :=
(SciSocketAddress fromString: '127.0.0.1') "Address of server machine"
family: SciSocketConstants::AFINET;
port: 2222.
secureSocket := SciSslSocket newStreamSocket.
(rv := secureSocket connect: anSciSocketAddress) isSciError
ifTrue:[ secureSocket close. self halt ].
(rv := secureSocket sslInitialize: config) isSslError
ifTrue: [ secureSocket close. self halt ].
(rv := secureSocket sslConnect) isSslError
ifTrue: [ secureSocket close. self halt ].
(rv := secureSocket sslVerifyCertificate) ~= 0
ifTrue: [ rv halt ].
(rv := secureSocket sslGetPeerCertificate) isSslError
ifTrue: [ rv halt ].
(rv := rv subject oneLine) isSslError
ifTrue: [ rv halt ].
(rv := secureSocket send: 'Hello World!' abrAsPSZ length: 12 startingAt: 1 flags: 0) isSslError
ifTrue: [ self halt ].
msg := ByteArray new: 4096.
(rv := secureSocket recv: msg length: 4096 startingAt: 1 flags: 0) isSslError
ifTrue: [ self halt ].
Transcript cr;
nextPutAll: 'SslClient Got -> ', msg asString trimNull, ' <- '.
secureSocket close. ] fork.