<?xml version="1.0"?>

<st-source>
<!-- 
Name: SSL
Notice: Copyright © 2008 Cincom Systems, Inc.  All Rights Reserved.
Comment: 
Secure Sockets Layer

This package provides implementation of Netscape's SSL protocol version 3.0. The implementation of the protocol itself is complete, it's limited only by the number of available encryption algorithms. 

Limitations

We now support most of the relevant SSL 3.0 cipher suites. We do not support the one cipher suite based on IDEA, the three cipher suites based on of Fortezza, nor the "exportable" variants of the strong cipher suites. This brings the list of supported cipher suites to the following:

	SSL_RSA_WITH_NULL_MD5
	SSL_RSA_WITH_NULL_SHA
	SSL_RSA_WITH_DES_CBC_SHA
	SSL_RSA_WITH_3DES_EDE_CBC_SHA
	SSL_RSA_WITH_RC4_128_MD5
	SSL_RSA_WITH_RC4_128_SHA
	SSL_DHE_DSS_WITH_DES_CBC_SHA
	SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
	SSL_DHE_RSA_WITH_DES_CBC_SHA
	SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
	SSL_DH_anon_WITH_DES_CBC_SHA
	SSL_DH_anon_WITH_RC4_128_MD5
	SSL_DH_anon_WITH_3DES_EDE_CBC_SHA

We do not support DH certificates, i.e., certificates with Diffie-Hellman parameters, however both RSA and DSA certificates are fully supported.

With client authentication we ignore the list of acceptable certificate authority names provided by the server in the CertificateRequest message and pass whatever certificate compatible with specified certificate types is available. It is up to the server to accept or reject it.

Usage

Following text will explain how to use this package. The main components of the public API are SSLContext, SSLSession and SSLConnection.

SSLContext represents a server/client context maintaining a collection of fairly static preconfigured communication parameters and options, like supported cipher suites, various certificate registries etc. It is also responsible to maintain the collection of resumable sessions for SSL servers.
It is a root component used by an application to create a suitable environment for SSL communication. Once specific parameters and options are set up an instance of SSLContext builds instances of SSLConnection upon request.

SSLConnection implements an actual connection between two parties. It is responsible for encryption/decryption of SSL records (basic units of SSL communication) and maintainance of negotiated encryption parameters. It provides the bulk of the public API e.g. connecting, accepting connection, closing connection, secure data streams. As such it is the component that is most exposed to an SSL application.

SSLSession is usually hidden from the application, except the case when an application wants to use several connections with the same party. It is much faster to "resume" an existing session for a new connection and use  previously negotiated encryption parameters than renegotiating a new parameter suite for each new connection. So for the cases when an application wants to resume an existing session it has to maintain a hold of it and hand it to the handshake API when connecting a new connection.

The usual usage pattern goes something like this. First an instance of a context has to be created and initialized with supported cipher suites:

	context := SSLContext newWithSecureCipherSuites.

Note that the collection of cipher suites can be specified explicitly using the SSLContext class>>suites: instance creation method.

Then an instance of a connection is built around an input-output binary stream. This is a stream provided by the lower level communication layer, usually a stream built from a TCP socket (Note that SSL is explicitly designed for connection-oriented protocols). So given a connected socket the stream can be built like this:

	ioStream := (aSocketAccessor asExternalConnection withEncoding: #binary) readAppendStream.

The connection is then created by the context as follows:

	connection := context connectionFor: ioStream.

Now we are ready to perform an SSL handshake. Each SSL connection connects a 'client' with a 'server',  playing two very different roles in the SSL handshake. To get a connection to handshake as a server send it message #accept. To get a connection to handshake as a client use message #connect.

	connection connect.

Once the handshake finishes we are almost ready to transfer data securely. All we need is to get a secure data stream from the connection. The protocol is the same as the one used for ExternalConnection (the ones used for creating socket streams), i.e. the SSLConnection accepts one of #appendStream, #readStream, #readAppendStream messages returning a stream using default encoding, or a specific encoding can be ordered with the #withEncoding: message, as in the following example.

	stream := (connection withEncoding: #binary) readAppendStream.

Note that SSL is not designed to transport application data on its own. Instead it is to be used for tunneling an application specific protocol used on top of it. It can be a completely custom proprietary protocol specifically designed for a given application or it can be protocol well known like HTTP for example. An important requirement on the application protocol is that it has to be self delimiting, i.e. it has to be able to determine the start and end of it's messages without any hints from SSL.

An important thing to remember is that to force the data written into a stream to leave SSL buffers and be sent to the other party the stream has to be explicitly flushed (same as with a normal socket stream).

	stream nextPutAll: #[1 2 3 4 5].
	stream flush.
	data := stream next: 5.
	Transcript show: data printString.

To close a connection send message #close to the data stream.

	stream close.

SSL specification requires connections to be properly closed with a close_notify alert sent to the other party. If there are circumstances in which it is not desirable to do that, message #shutdown can be sent to the SSLConnection to skip the notification. Note that #close is the prefered way though, because missing #close_notification creates a vulnerability to a truncation attack.

SSL Exceptions

An essential requirement for security technologies is being able to detect and stay in control when things go wrong. Therefore it is important to know how are these situations captured by the SSL framework. Exceptions are an obvious implementation choice. SSL exceptions are all subclassed from a generic SSLException class. They are divided into 2 categories, SSLErrors and SSLWarnings. SSLErrors are fatal exceptions, i.e. if an SSLError occurs the operation in progress cannot complete and has to be aborted, usually rendering the SSL connection itself unusable. SSLWarnings are resumable exceptions, they are meant to warn the user that there was a problem and it is up to the user (or the application) to decide if the operation should be completed or not. If the the warning is a problem serious enough given the circumstances, just return from the exception handler and the operation will be aborted, otherwise resume the exception to proceed with the operation. Keep in mind that most of the warnings report serious security issues though, so think twice before ignoring a warning.

Handshake and Certificates

The example as presented above would actually fail. The reason is that the context wasn't set up quite right. The default context settings are tuned to provide a secure connection and this cannot be achieved without authenticating the server party (server's usually don't care about client's identity so clients are not required to authenticate by default). Authentication is performed using X509 certificates. We can't go into the details of this complex topic here, so let's just say that a certificate is a digitally signed data structure containing information identifying the entity that the certificate was issued for, called the subject, a public key for a specific public key algorithm (like RSA), usually refered to as the subject public key, and identification of the entity that issued the certificate, the issuer. The signature of the certificate is there to prevent modification of the certificate contents. The signature is generated by the issuer. Since a signature can only be verified using the public key of the issuer, the issuer usually also has its own public key certificate. A set of certificates related by the subject-issuer relationship forms a certificate chain. The last certificate in the chain usually belongs to a well known certificate authority. If a party that needs to be authenticated (usually the server) provides a certificate chain to another party (the client) that knows the certificate of the certificate authority of the chain, then the client can verify authenticity of the whole chain. If the server further proves posession of the private key corresponding to the subject certificate of the chain, the client can be reasonably sure of authenticity of the server (provided that the private keys of the chain certificates were not compromised). These are the basic ideas behind the certificate based authentication used by SSL (For details on X509 certificates, please read the X509 RFC 2459).

In order to perform server authentication the client needs to be set up with a collection of 'trusted' certificate authority certificates. This collection is maintained in an instance of X509Registry. The contents of the registry is maintained using messages #addCertificate, #certificateFor: and #removeCertificate:. SSLContext needs to be linked to an instance of registry when created:

	registry := X509Registry new addCertificate: (X509RegistryTestResource new setUp; ca)
	ctx := SSLContext newWithAllCipherSuitesUsing: registry.

Note that the context creation methods without the registry parameter use 'X509Registry default' for the registry.

A server has to have both its own certificate chain and the corresponding private key registered with its SSLContext. Therefore these are registered with the context as a pair, an array with first item being a certificate chain and second item being the corresponding private key. The message to use to set up the context is #rsaCertificatePair:

	chainKeyPair := X509RegistryTestResource new setUp; fullChainKeyPair.
	ctx rsaCertificatePair: chainKeyPair.

The server presents its certificate chain to the client during SSL handshake. The client then validates the chain using its certificate registry. If the validation fails the client signals SSLBadCertificate warning. Other certificate related warnings are SSLCertificateExpired, SSLCertificateRevoked, SSLCertificateUnknown and SSLUnsupportedCertificate.

A simpler variant of client certificate setup can be used if the client party can obtain the server certificate via some other reliable means (for example using some other software package, e.g. one ca use an HTTPS enabled web browser to obtain the certificate of an HTTPS server). In this case the party that is validating a certificate received from the other party can maintain a list of certificates that it considers valid and match any incoming certificate with the list. If there is a bit-equivalent certificate found in the list, then the certificate is valid. The list of 'valid' certificates is maintained by the SSLContext. The list of valid certificates can be maintained using messages #addValidCertificate:, #validCertificateFor: and #removeValidCertificate:.

	certificate := X509Certificate fromString: X509RSAPrivateKey example1TestCertificate.
	context addValidCertificate: certificate

With the contexts setup the handshake has a pretty good chance of succeeding. There's one more issue to discuss though, and that is certificate subject validation. Remember that the whole purpose of certificates is authentication. The party to be authenticated sends a certificate which needs to be validated by the other party. SSL can do most of the validation by itself, but there's one check that only the application can perform reliably, that is certificate subject validation. The purpose of this check is to determine that the certificate belongs to the party that the application is actually trying to reach. Without this check an imposter can present his own perfectly valid certificate and impersonate the other party. This check is done by analyzing the subject's distinguished name embedded in the certificate to see that it is the name of the other party. This is the task of the subject validation block that should be provided by the application when the handshake is initiated. This block is passed as a parameter to #connectSubject:, which is a variant of #connect. For a server wishing to authenticate its clients the #accept variant is #acceptSubject:. The validation block takes one argument and it will be evaluated with a dictionary representing subject's distinguished name. The keys in the dictionary are so called attribute names and values are attribute values. For example web browsers are relying on a convention that the subject name attribute called 'commonName' or also just 'CN' contains a DNS name of the server site that the certificate was issued for. The block has to return a boolean, indicating validity of the subject name. If the block returns false, an SSLBadCertificate warning will be signaled. Here is an example subject validation block:

	connection connectSubject: [ :dnd | (dnd at: 'CN') = 'www.thesecureserver.com' ]

This states the requirement that the certificate presented by the server during the handshake has to have the specified value for the commonName attribute of the subject distinguished name.

Certificates for Signing

Certificates can have different purpose. SSL distinguishes certificates as the ones that can be used for signing and the ones that can be used for encryption or key exchange (A certificate should never be used for both, even though it may be technically possible). Certificates discussed previously would have to be encryption/key exchange certificates, for example encryption RSA certificates. However SSL can also accommodate the case when the party that needs to be authenticated has only a signing certificate.

A signing certificate has to be registered with the context as a signing certificate. If it is a certificate for RSA signing, message #rsaSigningCertificatePair: should be used. In case of DSS signing it should be message #dssCertificatePair: (DSS certificates are only used for signing). Apart from the signing certficate which will be used for authentication, a server also needs a pair of public/private encryption keys to be able to exchange a "secret" value with the client during the handshake. If such encryption key pair is not associated with server's certificate, a pair of so called "temporary" keys will have to be used. The type of keys obviously depends on the type of selected cipher suite. Similarly as with the certificate pair the key pair has to be registered with the SSLContext. In case of RSA cipher suite, message #rsaKeyPair: shoulf be used. With this setup the certificate will be used to authenticate the server. The private key of the certificate will be used to sign the temporary public key to prove to the client that the server really owns the private key for the certificate. The temporary public key will be sent to the client which will use the key to encrypt the "secret" value for the server. Server then uses the temporary private key to decrypt the secret value. Example server setup for this situation would look something like this:

	certificate := X509Certificate fromString: X509RSAPrivateKey example1TestCertificate.
	privateKey := (X509RSAPrivateKey fromString: X509RSAPrivateKey example1) getKey.
	context signingCertificatePair: (Array with: (Array with: certificate) with: privateKey).
	context rsaKeyPair: RSAEncryptionKey example1024BitKeyPair reverse

Diffie-Hellman Key Exchange

Because of the nature of Diffie-Hellman key exchange, there are several options how to use temporary keys for DHE cipher suites (Refer to the comment of the DH class for the details on the meaning of the various parameters mentioned below):

A) Both keys are precomputed and registered with the context using #dhKeyPair: message. In this case the first element of the pair is a 3-element array containing the group parameters p and g, and the public key y, in that order. The second element of the pair is a standalone private value x.

B) Just the group parameters are registered with the context and a fresh pair of the private/public values x/y are generated for each handshake. In this case the parameters are registered using #dhParameters: message as an (Array with: p with: g).

C) If nothing is registered with the context an SSLNoDHParameters exception is signaled. However if the exception is resumed, SSL will generate whole DH parameter suite on the fly and proceed the handshake with those. Note however that generation of the parameter p is time consuming and the delay caused by that may not be acceptable. In that case we recommend pregenerating the p and g parameters and use variant B above.

Client Authentication

Some servers may need to authenticate its clients. In this case the server should use #acceptSubject: instead of #accept. For the client to pass the authentication it has to have a signing certificate and a corresponding private key set in its SSLContext. Similarly as with the server, message rsaSigningCertificatePair: should be used for RSA certificates and message #dssCertificatePair: should be used for DSS certificates. The server will validate the client certificate with its certificate registry, its list of valid certificates and the subject validation block provided with the #acceptSubject: message. Note that SSL has provisions for a client to refuse to authenticate. In this case it is up to the server to decide if it allows the handshake to proceed without client authentication. Obviously this kind of decision has to be made at the application level. Therefore when the client refuses to authenticate the server connection will signal an SSLNoCertificate warning. The application should resume the warning if it wants to proceed, or return the warning if it wants to break the handshake off.

	[	connection acceptSubject: [ :dnd |
			((dnd at: 'O') = 'TrustMe Inc') & ('*Purchasing*' match: (dnd at: 'OU')) ]
	] on: SSLNoCertificate do: [ :ex | ex resume ]

Anonymous Handshake

By now you're probably wondering if you always have to deal with this messy certificate stuff. The answer is usually yes, unless you're in a situation when you don't need to  authenticate the other party because you are certain that you know who the other party is. In this situation you can do so called anonymous handshake. Keep in mind that this type of handshake is strongly discouraged though, because dropping authentication means dropping prevention of man-in-the-middle attacks.

Client side handshake is anonymous by default. Therefore anonymous handshake in SSL terms is the case when the server does not authenticate either. To setup a context for anonymous handshake there's no need to do any of the certificate registration mentioned above. To complete the handshake the server still needs a pair of public/private encryption keys for protection of the shared "secret". Same rules as for handshake with signing certificates apply.

In SSL, anonymity of the handshake is dictated by the selected cipher suite. SSL 3.0 defines only a few of those, they have DH_anon in the name and are all based on Diffie-Hellman key exchange.

There's no anonymous cipher suite defined for the RSA key exchange, and the SSLConnection will signal an SSLNoServerCertificate warning if the server doesn't have a suitable certificate. However this warning is again resumable, and if the handshake proceeds the server will skip the authentication and send temporary RSA key instead, thus possibly allowing the application to perform an anonymous handshake even though the cipher suite is not an anonymous one. Getting the server to perform an anonymous RSA handshake would look like following.

	context := SSLContext new initializeSuites: (Array with: SSLCipherSuite SSL_RSA_WITH_DES_CBC_SHA).
	context rsaKeyPair: RSAEncryptionKey example1024BitKeyPair reverse
	connection := context connectionFor: ioStream.
	[	connection accept
	] on: SSLNoServerCertificate do: [ :ex | ex resume ]

The client will refuse to handshake a non-anonymous cipher suite if the server doesn't authenticate. That is unless the #connect message is used (instead of #connectSubject:). Omitting the subject validation block is considered an indication that the client application is not interested to authenticate the server and thus allowing an anonymous handshake regardless of the chosen cipher suite.

Session Renegotiation

Occasionally, when an SSL connection is maintained for an extended time period, it might be desirable to renegotiate a new set of security parameters. SSL does have provisions to do that without rebuilding the connection from scratch. Renegotiation has to be initiated from the server side by sending message #renegotiate to the SSLConnection. This invokes a full SSL handshake. The client side SSLConnection handles renegotiation on its own, it is completely transparent for the client application.

Session Resumption

The last topic that we will cover here is session resumption. Negotiation of security parameters is expensive. Therefore it is often desirable to reuse the previously negotiated security parameters for additional connections to the same party. The results of the negotiation are captured in an instance of SSLSession. To get a new connection to reuse previously negotiated parameters it has to be built around the session that captures the parameters using method #connectionFor:using: instead of the previously mentioned #connectionFor:, for example:

	session := previousConnection session.
	newConnection := context connectionFor: aNewIOStream using: session.
	newConnection connect.

There's no need to use connectSubject: for session resumption, because the session caches the previously specified subject validation block. Ultimately it is up to the server to decide if it allows to resume a session. If resumption is refused the handshake will automatically fallback to full negotiation. A session has to be resumable to resume successfully (i.e. without doing the full negotiation). Session resumability can be tested with #isResumable message. A server context does not allow session resumption by default, therefore the sessions it creates will be non-resumable. To get the server context to create resumable sessions it has to receive #allowResumableSessions message. Any session can be explicitly made non-resumable using message #beNonResumable.

DbIdentifier: bear73
DbTrace: 116040
DevelopmentPrerequisites: #(#(#package 'SecurityBase' '') #(#package 'MD5' '') #(#package 'SHA' '') #(#package 'ARC4' '') #(#package 'DES' '') #(#package 'RSA' '') #(#package 'DH' '') #(#package 'DSA' '') #(#package 'X509' ''))
PackageName: SSL
Parcel: #('SSL')
PrerequisiteParcels: #(#('SecurityBase' '') #('MD5' '') #('SHA' '') #('ARC4' '') #('DES' '') #('RSA' '') #('DH' '') #('DSA' '') #('X509' ''))
PrintStringCache: (751 1,mkobetic)
Version: 7.6
Date: 12:31:58 pm February 1, 2008
 -->
<time-stamp>From VisualWorks®, 7.6 of February 1, 2008 on February 1, 2008 at 12:31:58 pm</time-stamp>


<do-it>(Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned.  Choose terminate or close.']</do-it>

<class>
<name>SSLException</name>
<environment>Security</environment>
<super>Core.Error</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLException</class-id>
<body>This is a common superclass for all SSL exceptions. Many of these exceptions are coupled with corresponding SSL alerts. The #sendIn: and #sendIn:as: methods are added which should send out corresponding SSL alerts in addition to signaling the exception when required.

Subclasses must implement the following messages:
	services
		sendIn:as:

</body>
</comment>

<class>
<name>SSLWarning</name>
<environment>Security</environment>
<super>Security.SSLException</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLWarning</class-id>
<body>This is a common superclass for all resumable SSL errors. It implements the #sendIn: method to send a corresponding SSL alert to the other party only if the exception handler returns (unwinding the stack). If the exception is resumed no alert is sent and the operation proceeds normally.
</body>
</comment>

<class>
<name>SSLCertificateWarning</name>
<environment>Security</environment>
<super>Security.SSLWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCertificateWarning</class-id>
<body>This is a common superclass for all certificate warnings. It allows to provide a common handler for all of them without having to enumerate the full list.

</body>
</comment>

<class>
<name>SSLError</name>
<environment>Security</environment>
<super>Security.SSLException</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLError</class-id>
<body>This is a common superclass for all fatal SSL errors. It implements the #sendIn: method to send a corresponding SSL alert to the other party before signaling the exception.
</body>
</comment>

<class>
<name>SSLMessageError</name>
<environment>Security</environment>
<super>Security.SSLError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLMessageError</class-id>
<body>This is a common superclass for message level SSL errors.

</body>
</comment>

<class>
<name>SSLRecordError</name>
<environment>Security</environment>
<super>Security.SSLError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLRecordError</class-id>
<body>This is a common superclass for record level SSL errors.


</body>
</comment>

<class>
<name>SSLCertificateUnknown</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCertificateUnknown</class-id>
<body>SSL3.0 Spec: Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable.</body>
</comment>

<class>
<name>SSLMessage</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLMessage</class-id>
<body>This class is the common superclass of all supported SSL message subprotocols. Subclasses of this class represent different subprotocols of SSL. Messages have to know how to write itself onto a byte stream and how to read themselves back in the context of a given SSL connection.

Subclasses must implement:
	instance protocol:
		readFrom:in:
		writeOn:in:
		protocol</body>
</comment>

<class>
<name>HandshakeMessage</name>
<environment>Security</environment>
<super>Security.SSLMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.HandshakeMessage</class-id>
<body>This class is a common superclass for messages of the handshake subprotocol of SSL message layer. As the handshake subprotocol is fairly rich with a lot of options introduced by different cipher suites, there is a bunch of subclasses implementing individual messages of the subprotocol.

Subclasses must implement:
	class protocol:
		type

Shared Class Variables:
	CodeToMessageClassMap	&lt;Dictionary key: SmallInteger value: Class&gt; maps handshake message codes to classes</body>
</comment>

<class>
<name>KeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.KeyExchangeMessage</class-id>
<body>This is an SSL handshake message.
</body>
</comment>

<class>
<name>ServerKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.KeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>signature </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ServerKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.

Subclasses must implement the following messages:
	reading/writing
		parametersLength
		writeParametersOn:
		readParametersFrom:

Instance Variables:
	signature	&lt;ByteArray&gt;	a signed digest of public server key or parameters

</body>
</comment>

<class>
<name>ServerRSAKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.ServerKeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>rsaModulus rsaExponent </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ServerRSAKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	rsaExponent	&lt;ByteArray&gt;	public RSA exponent
	rsaModulus	&lt;ByteArray&gt;	public RSA modulus
</body>
</comment>

<class>
<name>SSLSession</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>id majorVersion minorVersion context peerCertificate cipherSuite secret isServer subjectValidator </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLSession</class-id>
<body>This class represents a session between two parties which may use only a single connection for the whole time or open and close connections in its course as the needs arise. It is also possible to run several connections in parallel within the same session. Session maintains session details like the shared secret or selected cipher suite for its connection(s) and implements the handshaking process.

Instance Variables:
	id	&lt;ByteArray&gt; session identifier declared as "opaque SessionID&lt;0..32&gt;", i.e. 0-32 uninterpreted bytes
	majorVersion	&lt;SmallInteger&gt; major part of the negotiated version number
	minorVersion	&lt;SmallInteger&gt; minor part of the negotiated version number
	context	&lt;SSLContext&gt; the general SSL context
	peerCertificate	&lt;X509Certificate&gt; certificate of the other party in the connection
	cipherSuite	&lt;SSLCipherSuite&gt; negotiated cipher spec
	secret	&lt;ByteArray&gt; the established common secret declared as "opaque MasterSecret[48]", i.e. 48 uninterpreted bytes
	isServer	&lt;Boolean&gt; the role of this party in the connection (server/client)
	subjectValidator	&lt;BlockClosure&gt;	one argument block provided by the application to validate the other party's certificate subject name. It's argument will be a dictionary of attribute name-&gt;values and should return true or false when invoked.</body>
</comment>

<class>
<name>SSLEncodedStreamConstructor</name>
<environment>Security</environment>
<super>Core.InternalEncodedStreamConstructor</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLEncodedStreamConstructor</class-id>
<body>This is a standard VW stream constructor allowing the usual stream building APIs to be used with SSLConnection (which should behave as any other external connection in this respect).

</body>
</comment>

<class>
<name>CertificateVerifyMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>signature </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.CertificateVerifyMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	signature	&lt;ByteArray&gt;	signed digest of handshake messages

</body>
</comment>

<class>
<name>HelloRequestMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.HelloRequestMessage</class-id>
<body>This is an SSL handshake message.

</body>
</comment>

<class>
<name>ClientKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.KeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ClientKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.
</body>
</comment>

<class>
<name>SSLCertificateExpired</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCertificateExpired</class-id>
<body>"SSL3.0 Spec: A certificate has expired or is not currently valid."
</body>
</comment>

<class>
<name>SSLHandshake</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>clientHello serverHello serverCertificate serverKeyExchange certificateRequest serverHelloDone clientCertificate clientKeyExchange certificateVerify finished md5 sha connection readStream writeStream </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLHandshake</class-id>
<body>This class captures the dynamic aspects of an SSL handshake and in concert with SSLSession facilitates the handshake as well.

Instance Variables:
	clientHello	&lt;ClientHelloMessage&gt;	handshake message log
	serverHello	&lt;ServerHelloMessage&gt;	handshake message log
	serverCertificate	&lt;CertificateMessage&gt;	handshake message log
	serverKeyExchange	&lt;ServerKeyExchangeMessage&gt;	handshake message log
	certificateRequest	&lt;CertificateRequestMessage&gt;	handshake message log
	serverHelloDone	&lt;ServerHelloDoneMessage&gt;	handshake message log
	clientCertificate	&lt;CertificateMessage&gt;	handshake message log
	clientKeyExchange	&lt;ClientKeyExchangeMessage&gt;	handshake message log
	certificateVerify	&lt;CertificateVerifyMessage&gt;	handshake message log
	finished	&lt;FinishedMessage&gt;	handshake message log
	md5	&lt;MD5&gt; 	running MD5 digest of the handshake messages
	sha	&lt;SHA&gt;	running SHA digest of the handshake messages
	connection	&lt;SSLConnection&gt;	the connection that is being handshaked over
	readStream	&lt;FragmentStream&gt;	stream for incoming handshake messages
	writeStream	&lt;FragmentStream&gt;	stream for outgoing handshake messages

</body>
</comment>

<class>
<name>SSLRecord</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>protocol majorVersion minorVersion fragment size </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLRecord</class-id>
<body>This class represents the SSL record layer. SSL record is the basic unit of SSL communication. It is a chunk of possibly encrypted and signed binary data of up to 16K size.

Instance Variables:
	protocol	&lt;SmallInteger&gt; type of messages carried by the record
	majorVersion	&lt;SmallInteger&gt; major part of the SSL version number. SSL 3.0 =&gt; 3
	minorVersion	&lt;SmallInteger&gt; minor part of the SSL version number. SSL 3.0 =&gt; 0
	fragment	&lt;ByteArray&gt; data
	size	&lt;SmallInteger&gt; record size
</body>
</comment>

<class>
<name>SSLShort20Challenge</name>
<environment>Security</environment>
<super>Security.SSLWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLShort20Challenge</class-id>
<body>Warns that the supplied challenge in SSL 2.0 hello is very short. The client has the option to proceed anyway.

</body>
</comment>

<class>
<name>SSLIllegalParameter</name>
<environment>Security</environment>
<super>Security.SSLMessageError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLIllegalParameter</class-id>
<body>SSL3.0Spec: A field in the handshake was out of range or inconsistent with other fields.  This is always fatal.

</body>
</comment>

<class>
<name>SSLNoCertificate</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLNoCertificate</class-id>
<body>SSL3.0Spec: A no_certificate alert message may be sent in response to a certification request if no appropriate certificate is available.

</body>
</comment>

<class>
<name>HelloMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>majorVersion minorVersion randomValue sessionId </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.HelloMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	majorVersion	&lt;SmallInteger&gt; major protocol version number
	minorVersion	&lt;SmallInteger&gt;	minor protocol version number
	randomValue	&lt;ByteArray&gt;	generated random value
	sessionId	&lt;ByteArray&gt;	identifier of an SSL session

</body>
</comment>

<class>
<name>SSLBadRecordMAC</name>
<environment>Security</environment>
<super>Security.SSLRecordError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLBadRecordMAC</class-id>
<body>SSL3.0Spec: This alert is returned if a record is received with an incorrect MAC.  This message is always fatal.

This is an indication that the contents of the communication may have been tampered with.
</body>
</comment>

<class>
<name>SSLUnsupportedCertificate</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLUnsupportedCertificate</class-id>
<body>SSL3.0 Spec: A certificate was of an unsupported type.</body>
</comment>

<class>
<name>AlertMessage</name>
<environment>Security</environment>
<super>Security.SSLMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>severityCode descriptionCode description </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.AlertMessage</class-id>
<body>This class implements the Alert subprotocol of SSL message layer.

Instance Variables:
	severityCode	&lt;SmallInteger&gt; 1 = fatal alert, 0 = warning
	descriptionCode	&lt;SmallInteger&gt; type of alert
	description	&lt;Symbol&gt; standard name of the alert (corresponds to description code)

Shared Class Variables:
	CodeToExceptionMap &lt;Dictionary key: Integer value: Class&gt; maps alert codes to exceptions
	CodeToMessageMap &lt;Dictionary key: Integer value: AlertMessage&gt; maps alert codes to alert messages</body>
</comment>

<class>
<name>InputOutputStream</name>
<environment>Security</environment>
<super>Core.Stream</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>in out </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.InputOutputStream</class-id>
<body>This stream combines a "readable" stream and a "writable" stream into a single "read-writeable" stream. It simply forwards basic streaming messages to the apropriate substream. SSL uses it to combine incoming and outgoing fragment stream into a single read-append "data" stream.

Instance Variables:
	in	&lt;ReadStream&gt; incoming data stream
	out	&lt;WriteStream&gt; outgoing data stream

</body>
</comment>

<class>
<name>SSLHandshakeFailure</name>
<environment>Security</environment>
<super>Security.SSLMessageError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLHandshakeFailure</class-id>
<body>SSL3.0 Spec: Reception of a handshake_failure alert message indicates that the sender was unable to negotiate an acceptable set of security parameters given the options available. This is a fatal error.

</body>
</comment>

<class>
<name>SSLUnexpectedMessage</name>
<environment>Security</environment>
<super>Security.SSLMessageError</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLUnexpectedMessage</class-id>
<body>SSL3.0 Spec: An inappropriate message was received. This alert is always fatal and should never be observed in communication between proper implementations.

</body>
</comment>

<class>
<name>ClientRSAKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.ClientKeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>encryptedPremasterSecret </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ClientRSAKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	encryptedPremasterSecret	&lt;ByteArray&gt;	pre-master secret generated by the client

</body>
</comment>

<class>
<name>ServerHelloDoneMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ServerHelloDoneMessage</class-id>
<body>This is an SSL handshake message.

</body>
</comment>

<class>
<name>ClientDHKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.ClientKeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>yc </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ClientDHKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	yc	&lt;LargePositiveInteger&gt; the public value from the client
</body>
</comment>

<class>
<name>ServerDHKeyExchangeMessage</name>
<environment>Security</environment>
<super>Security.ServerKeyExchangeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>p g ys </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ServerDHKeyExchangeMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	p	&lt;LargePositiveInteger&gt; the DH prime parameter
	g	&lt;Integer&gt; the DH generator parameter
	ys	&lt;LargePositiveInteger&gt; the public value from the server

</body>
</comment>

<class>
<name>CertificateRequestMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>certificateTypes authorityNames </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.CertificateRequestMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	authorityNames	&lt;(Collection of: Name)&gt; list of acceptable certificate authority names
	certificateTypes	&lt;(Collection of: Symbol)&gt; list of acceptable certificate types (defined by CertificateTypeToCode)

Shared Class Variables:
	CertificateTypes	&lt;Array of: Symbol&gt;maps certificate type code to name as defined by the SSL 3.0 Spec (see class method #buildCertificateTypes)

</body>
</comment>

<class>
<name>SSLConnection</name>
<environment>Security</environment>
<super>Core.EventManager</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>session activeReadCipherSpec activeWriteCipherSpec pendingReadCipherSpec pendingWriteCipherSpec serverRandom clientRandom writeMACSecret readMACSecret writeKey readKey writeIV readIV writeSequenceNumber readSequenceNumber writeStream readStream ioStream recordCache maxRecordsToCache mutex </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLConnection</class-id>
<body>This class represents and actual connection between two parties. It is responsible for encryption/decryption of SSL records and maintainance of negotiated encryption parameters. It provides the bulk of the public API e.g. connecting, accepting connection, closing connection, sending and receiving messages.

Instance Variables:
	session	&lt;SSLSession&gt;
	activeReadCipherSpec	&lt;SSLCipherSpec&gt; describes algorithms used to decrypt incoming records
	activeWriteCipherSpec	&lt;SSLCipherSpec&gt; describes algorithms used to encrypt outgoing records
	pendingReadCipherSpec	&lt;SSLCipherSpec&gt; used for handshaking purposes
	pendingWriteCipherSpec	&lt;SSLCipherSpec&gt; used for handshaking purposes
	serverRandom	&lt;ByteArray&gt; random 32 bytes (defined below) chosen by the server
	clientRandom	&lt;ByteArray&gt; random 32 bytes (defined below) chosen by the client
	writeMACSecret	&lt;ByteArray&gt; used in MAC operations on data written
	readMACSecret	&lt;ByteArray&gt; used in MAC operations on data read
	writeKey	&lt;ByteArray&gt; bulk cipher key for encryption of outgoing data
	readKey	&lt;ByteArray&gt; bulk cipher key for decryption of incoming data
	writeIV	&lt;ByteArray&gt; initialization vector for the outgoing bulk encryption (used by CBC ciphers)
	readIV	&lt;ByteArray&gt; initialization vector for the incoming bulk encryption (used by CBC ciphers)
	writeSequenceNumber	&lt;Number&gt; sequence number for transmitted messagess, declared as unit64
	readSequenceNumber	&lt;Number&gt; sequence number for received messages, declared as uint64
	writeStream	&lt;FragmentStream&gt;	stream for writing outgoing SSLRecords
	readStream	&lt;FragmentStream&gt;	stream for reading incoming SSLRecords
	ioStream	&lt;ReadAppendStream&gt;	actual low-level io stream, the source of incoming bytes and target of outgoing bytes.
	recordCache	&lt;OrderedCollection of: SSLRecord&gt;	a pool of unused records
	maxRecordsToCache	&lt;SmallInteger&gt;	the maximum number of unused records to cache
	mutex	&lt;RecursionLock&gt;	cache mutex

Shared Class Variables:
	MaxRecordsToCache &lt;SmallInteger&gt; the default maximum number of unused records to cache for reuse

SSL Random is declared as follows (For our purposes it is simply a 32-byte ByteArray)

	struct {
		uint32 gmt_unix_time;		// current time and date in standard UNIX 32-bit format
		opaque random_bytes[28];	// 28 bytes generated by a secure random number generator
	} Random;
</body>
</comment>

<class>
<name>FragmentStream</name>
<environment>Security</environment>
<super>Core.Stream</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>fragments fragmentIndex fragmentPosition newFragmentProvider newFragmentMessage </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.FragmentStream</class-id>
<body>This class is an internal stream iterating over a collection of subcollections (a.k.a. fragments). It grows during both write and read according to configured growth policy represented by fragment provider and fragment message. Whenever the stream runs out of fragments it sends the fragment provider the fragment message expecting a new fragment as a result of it. There is a predefined no growth policy which raises EndOfStream exception when the stream runs out of fragments. The default policy is constant fragment policy which adds a new fragment of the same size as the first fragment when there is a need to grow.

The SSL protocol uses this stream for translation from/to record layer to/from message layer. Records are blocks of data of up to 16K size. There can be multiple messages in one record as well as there can be one message spanning several records.

Instance Variables:
	fragments	&lt;OrderedCollection of: ByteArray&gt; collection of fragments
	fragmentIndex	&lt;SmallInteger&gt; index of the current fragment in the collection of fragments
	fragmentPosition	&lt;SmallInteger&gt; index of the next element within the current fragment
	newFragmentProvider	&lt;FragmentStream | SSLConnection&gt; Provider of new fragments, by default the stream itself.
	newFragmentMessage	&lt;Symbol&gt; selector of the message used to ask the fragment provider for a new fragment. By default #constantFragment
</body>
</comment>

<class>
<name>ServerHelloMessage</name>
<environment>Security</environment>
<super>Security.HelloMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>cipherSuite </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ServerHelloMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	cipherSuite	&lt;SSLCipherSuite&gt;	cipher suite selected for this SSL session

</body>
</comment>

<class>
<name>SSLCipherSuite</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>keyExchange cipherSpec code </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCipherSuite</class-id>
<body>This class represents a full suite of encryption techniques used to establish and conduct secure communication. This includes information represented by a cipher spec plus the handshaking technique used to establish common secret between the client and server. The suite is negotiated during the initial phase of handshaking process. The list of supported cipher suites is sent by the client to the server and server picks one and sends it back to the client. SSL Specification defines the set of supported cipher suites.

Instance Variables:
	keyExchange	&lt;SSLKeyExchange&gt; the key exchange algorithm
	cipherSpec	&lt;SSLCipherSpec&gt; the rest of encryption algorithms
	code	&lt;SmallInteger&gt; standard code of given cipher suite

Shared Variables:
	Codes	&lt;Dictionary key: SmallInteger value: Symbol&gt; maps standard suite codes to standard suite names
</body>
</comment>

<class>
<name>SSLKeyExchange</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLKeyExchange</class-id>
<body>SSL handshake algorithm.

Subclasses must implement the following messages:
	handshaking
		clientKeyExchangeMessageClass
		receiveServerKeyExchange:
		sendClientKeyExchange:
		sendServerKeyExchange:
		serverKeyExchangeMessageClass
	printing
		printOn:</body>
</comment>

<class>
<name>SSLBlockPadding</name>
<environment>Security</environment>
<super>Security.BlockPadding</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLBlockPadding</class-id>
<body>SSL specific block padding algorithm as described in the specification.

</body>
</comment>

<class>
<name>ChangeCipherSpecMessage</name>
<environment>Security</environment>
<super>Security.SSLMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ChangeCipherSpecMessage</class-id>
<body>This class implements change cipher subprotocol of SSL message layer. There's only one message defined in this subprotocol, so there are no subclasses of this class.
</body>
</comment>

<class>
<name>ClientHelloMessage</name>
<environment>Security</environment>
<super>Security.HelloMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>cipherSuites </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ClientHelloMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	cipherSuites	&lt;(Collection of: SSLCipherSuite)&gt;	list of acceptable cipher suites

</body>
</comment>

<class>
<name>ClientHello20Message</name>
<environment>Security</environment>
<super>Security.ClientHelloMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.ClientHello20Message</class-id>
<body>ClientHello from SSL 2.0.

</body>
</comment>

<class>
<name>SSLBadCertificate</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLBadCertificate</class-id>
<body>SSL3.0 Spec: A certificate was corrupt, contained signatures that did not verify correctly, etc.

This exception is also signaled if the certificate subject's distinguished name failed to satisfy the subject validation block provided by the application.
</body>
</comment>

<class>
<name>SSLContext</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>ciphers random sessions lastSessionId parameters validCertificates certificateRegistry </inst-vars>
<class-inst-vars>defaultRandom </class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLContext</class-id>
<body>This class represents server/client SSL context maintaining a collection of fairly static preconfigured communication parameters and options, as supported cipher suites, various certificate registries etc. It is also responsible to maintain the collection of resumable sessions for SSL servers.

It is a root component used by an application to create a suitable environment for SSL communication by setting up context parameters and options. Once set up it builds instances of SSL connection upon request.

Instance Variables:
	ciphers	&lt;OrderedCollection of: SSLCipherSuite&gt; supported cipher suites
	random	&lt;DSSRandom&gt; a random generator to use for all PRNG operations
	sessions	&lt;Dictionary key: ByteArray value: SSLSession&gt; sessions that are resumable, keyed by session id
	lastSessionId	&lt;LargePositiveInteger&gt; id cache for generation of new session ids
	parameters	&lt;Dictionary&gt; optional context paramaters like certificates, keys, various handshake options
	validCertificates	&lt;Dictionary&gt; registry of certificates recognized as valid, keyed by subject distinguished names
	certificateRegistry	&lt;X509Registry&gt; registry of recognized CA certificates

Class Instance Variables:
	defaultRandom	&lt;DSSRandom&gt; the default random generator to use for all PRNG operations

</body>
</comment>

<class>
<name>SSLNoDHParameters</name>
<environment>Security</environment>
<super>Security.SSLWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLNoDHParameters</class-id>
<body>Server side warning that the context is not configured with DH parameters. If it is resumed the parameters will be generated.</body>
</comment>

<class>
<name>SSLCipherSpec</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>bulkCipher mac signingPad1 signingPad2 </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCipherSpec</class-id>
<body>This class represents the encryption policy used to encrypt the communication in an established SSL connection. Since the key exchange algorithm is only used during handshaking, cipher spec captures only the symetric "bulk" cipher algorithm and the signing algorithm. Cipher spec is also used to represent active/pending read/write state of an SSL connection.

Instance Variables:
	bulkCipher	&lt;BlockCipher&gt; implementation of the data encryption algorithm (e.g. DES)
	mac	&lt;Hash&gt; implementation of a secure hash function (SHA or MD5)
	signingPad1	&lt;ByteArray&gt;
	signingPad2	&lt;ByteArray&gt;
</body>
</comment>

<class>
<name>SSLCertificateRevoked</name>
<environment>Security</environment>
<super>Security.SSLCertificateWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLCertificateRevoked</class-id>
<body>SSL3.0 Spec: A certificate was revoked by its signer.
</body>
</comment>

<class>
<name>SecretMaterialStream</name>
<environment>Security</environment>
<super>Security.FragmentStream</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>secret </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SecretMaterialStream</class-id>
<body>SSL computes its security parameters using a formula that generates chunks of the secret "material". This class allows to wrap the formula in a fragment generation message to provide streaming over the secret "material" for easier initialization of the security parameters.

Instance Variables:
	secret	&lt;ByteArray&gt;	A secret value used in the material generation algorithm

</body>
</comment>

<class>
<name>SSLNoServerCertificate</name>
<environment>Security</environment>
<super>Security.SSLWarning</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLNoServerCertificate</class-id>
<body>This exception is signaled when the server cannot find a certificate for its authentication.
</body>
</comment>

<class>
<name>FinishedMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>md5Hash shaHash </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.FinishedMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	md5Hash	&lt;ByteArray&gt;	a digest of messages exchanged in the handshake
	shaHash	&lt;ByteArray&gt;	a digest of messages exchanged in the handshake

</body>
</comment>

<class>
<name>SSLDHKeyExchange</name>
<environment>Security</environment>
<super>Security.SSLKeyExchange</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>type signing dh key </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLDHKeyExchange</class-id>
<body>SSL key exchange algorithm.

Instance Variables:
	type	&lt;Symbol&gt; what kind of key exchange, ephemeral/fixed/anonymous
	signing	&lt;Symbol&gt; signing algorithm, DSS/RSA
	dh	&lt;DH&gt; algorithm instance
	key	&lt;LargePositiveInteger&gt; the public key of the other party
</body>
</comment>

<class>
<name>CertificateMessage</name>
<environment>Security</environment>
<super>Security.HandshakeMessage</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>certificateChain </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.CertificateMessage</class-id>
<body>This is an SSL handshake message.

Instance Variables:
	certificateChain	&lt;(SequenceableCollection of: X509Certificate)&gt;

</body>
</comment>

<class>
<name>SSLRSAKeyExchange</name>
<environment>Security</environment>
<super>Security.SSLKeyExchange</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>key </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Net-SSL</category>
<attributes>
<package>SSL</package>
</attributes>
</class>

<comment>
<class-id>Security.SSLRSAKeyExchange</class-id>
<body>SSL key exchange algorithm.

Instance Variables:
	key	&lt;RSAPrivateKey | RSAPublicKey&gt; key cache
</body>
</comment>

<shared-variable>
<name>MaxRecordsToCache</name>
<environment>Security.SSLConnection</environment>
<private>false</private>
<constant>false</constant>
<category>constants</category>
<initializer>Security.SSLConnection defaultMaxRecordsToCache</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<shared-variable>
<name>CodeToMessageClassMap</name>
<environment>Security.HandshakeMessage</environment>
<private>false</private>
<constant>false</constant>
<category>message types</category>
<initializer>nil</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<shared-variable>
<name>CertificateTypes</name>
<environment>Security.CertificateRequestMessage</environment>
<private>false</private>
<constant>false</constant>
<category>Codes</category>
<initializer>CertificateRequestMessage buildCertificateTypes</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<shared-variable>
<name>Codes</name>
<environment>Security.SSLCipherSuite</environment>
<private>false</private>
<constant>false</constant>
<category>constants</category>
<initializer>SSLCipherSuite buildCodes</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<shared-variable>
<name>CodeToExceptionMap</name>
<environment>Security.AlertMessage</environment>
<private>false</private>
<constant>false</constant>
<category>alert messages</category>
<initializer>AlertMessage rebuildCodeToExceptionMap</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<shared-variable>
<name>CodeToMessageMap</name>
<environment>Security.AlertMessage</environment>
<private>false</private>
<constant>false</constant>
<category>alert messages</category>
<initializer>AlertMessage rebuildCodeToMessageMap</initializer>
<attributes>
<package>SSL</package>
</attributes>
</shared-variable>

<methods>
<class-id>Security.SSLException</class-id> <category>services</category>

<body package="SSL" selector="alertMessage">alertMessage

	| code |
	code := self class alertCode.
	^code isNil
		ifTrue: [ SSLException new
				messageText: (
					(#InvalidAlertCode &lt;&lt; #security &gt;&gt; 'No corresponding SSLAlert for &lt;1s&gt;')
						expandMacrosWith: self printString);
				parameter: self;
				raise ]
		ifFalse: [ AlertMessage code: code ]</body>

<body package="SSL" selector="sendIn:">sendIn: aConnection
"Signalling and SSLException often requires to send a corresponding SSLAlert across the wire.
This is the method that supposed to do all that's necessary and thus should be the prefered way
to raise an SSLException."

	self sendIn: aConnection as: self alertMessage</body>

<body package="SSL" selector="sendIn:as:">sendIn: aConnection as: anAlert
"Signalling and SSLException often requires to send a corresponding SSLAlert across the wire.
This is the method that supposed to do all that's necessary and thus should be the prefered way
to raise an SSLException."

	^self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.SSLException class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^nil</body>
</methods>

<methods>
<class-id>Security.SSLWarning</class-id> <category>services</category>

<body package="SSL" selector="sendIn:as:">sendIn: aConnection as: anAlert
"Signaling an SSLException often requires to send a corresponding SSLAlert across the wire.
SSLWarnings can be ignored by the user, by resuming the warning,
otherwise the corresponding alert will be sent across."

	[	self raise
	] ifCurtailed: [ aConnection sendMessage: anAlert ]</body>
</methods>

<methods>
<class-id>Security.SSLWarning class</class-id> <category>testing</category>

<body package="SSL" selector="mayResume">mayResume

	^true</body>
</methods>

<methods>
<class-id>Security.SSLCertificateWarning class</class-id> <category>handshaking</category>

<body package="SSL" selector="replacementFor:">replacementFor: anException
"Used to resignal X509 exceptions"

	^self new
		messageText: anException messageText;
		parameter: anException;
		yourself</body>
</methods>

<methods>
<class-id>Security.SSLError</class-id> <category>services</category>

<body package="SSL" selector="sendIn:as:">sendIn: aConnection as: anAlert
"Signaling an SSLException often requires to send a corresponding SSLAlert across the wire.
SSLErrors are always fatal and should always send an alert across."

	aConnection sendMessage: anAlert.
	self raise</body>
</methods>

<methods>
<class-id>Security.SSLCertificateUnknown class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^46</body>
</methods>

<methods>
<class-id>Security.SSLMessage</class-id> <category>testing</category>

<body package="SSL" selector="isAlert">isAlert

	^false</body>

<body package="SSL" selector="isHandshake">isHandshake

	^false</body>
</methods>

<methods>
<class-id>Security.SSLMessage</class-id> <category>accessing</category>

<body package="SSL" selector="protocol">protocol

	^self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.SSLMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	self subclassResponsibility</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.SSLMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.HandshakeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readByteLengthFrom:in:">readByteLengthFrom: aByteStream in: aConnection

	^(((aByteStream next bitShift: 8) + aByteStream next) bitShift: 8) + aByteStream next</body>

<body package="SSL" selector="writeByteLength:on:in:">writeByteLength: length on: aByteStream in: aConnection

	aByteStream
		nextPut: (length bitShift: -16);
		nextPut: ((length bitShift: -8) bitAnd: 255);
		nextPut: (length bitAnd: 255)</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	aByteStream nextPut: self type</body>
</methods>

<methods>
<class-id>Security.HandshakeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="protocol">protocol

	^22</body>

<body package="SSL" selector="type">type

	^self class type</body>
</methods>

<methods>
<class-id>Security.HandshakeMessage</class-id> <category>testing</category>

<body package="SSL" selector="isHandshake">isHandshake

	^true</body>
</methods>

<methods>
<class-id>Security.HandshakeMessage class</class-id> <category>message types</category>

<body package="SSL" selector="codeToMessageClassMap">codeToMessageClassMap

	^CodeToMessageClassMap isNil
		ifTrue: [self rebuildCodeToMessageClassMap]
		ifFalse: [CodeToMessageClassMap]</body>

<body package="SSL" selector="rebuildCodeToMessageClassMap">rebuildCodeToMessageClassMap
"(((self rebuildCodeToMessageClassMap)))"

	CodeToMessageClassMap := IdentityDictionary new.
	(self allSubclasses select: [:c | c class includesSelector: #type]) do: [ :c |
		CodeToMessageClassMap at: c type put: c ].
	^CodeToMessageClassMap</body>

<body package="SSL" selector="type">type

	^self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.HandshakeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| type |
	type := aByteStream next.
	^(self codeToMessageClassMap at: type ifAbsent: [
		SSLIllegalParameter new
			messageText: (
				(#UnknownHandshakeMsg1s &lt;&lt; #security &gt;&gt; 'Unknown handshake message type &lt;1s&gt;')
					expandMacrosWith: type printString);
			parameter: type;
			raise ]
	) readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ServerKeyExchangeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="parametersLength">parametersLength

	^self subclassResponsibility</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	self readParametersFrom: aByteStream.
	length := length - self parametersLength.
	length isZero ifFalse: [ | vectorLength |
		vectorLength := (aByteStream next bitShift: 8) bitOr: aByteStream next.
		length - vectorLength = 2 ifFalse: [
			SSLIllegalParameter new
				messageText: (
					(#InvalidSigLength1s2s &lt;&lt; #security &gt;&gt; 'Signature vector length &lt;1s&gt;does not match stated signature length &lt;2s&gt;')
						expandMacrosWith: vectorLength printString
						with: length printString);
				parameter: (Array with: vectorLength with: length);
				raise ].
		signature := aByteStream next: vectorLength ].
	^self</body>

<body package="SSL" selector="readParametersFrom:">readParametersFrom: aByteStream

	^self subclassResponsibility</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	self	writeByteLength: (
			self parametersLength
			+ (signature isNil
				ifTrue: [0]
				ifFalse: [signature size + 2 "vectorLength"]))
		on: aByteStream in: aConnection.
	self writeParametersOn: aByteStream.
	signature notNil ifTrue: [ | vectorLength |
		"It's actually just the TLS spec that states it clearly that digitally-signed element is encoded as
		an opaque variable vector &lt;0..2^16-1&gt;, which in turn should be prefixed by its length.
		See RFC2246 section 4.7 'Cryptographic attributes' and 4.3 'Vectors'"
		vectorLength := signature size.
		aByteStream nextPut: ((vectorLength bitShift: -8) bitAnd: 255); nextPut: (vectorLength bitAnd: 255).
		aByteStream nextPutAll: signature ]</body>

<body package="SSL" selector="writeParametersOn:">writeParametersOn: aByteStream

	^self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.ServerKeyExchangeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="signature">signature

	^signature</body>

<body package="SSL" selector="signature:">signature: aByteArray

	signature := aByteArray</body>
</methods>

<methods>
<class-id>Security.ServerKeyExchangeMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^12</body>
</methods>

<methods>
<class-id>Security.ServerKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^aConnection cipherSuite keyExchange serverKeyExchangeMessageClass
		readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ServerRSAKeyExchangeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="parametersLength">parametersLength

	^4 "lengths" + rsaModulus size + rsaExponent size</body>

<body package="SSL" selector="readParametersFrom:">readParametersFrom: aByteStream

	| rsaModLength rsaExpLength |
	rsaModLength := (aByteStream next bitShift: 8) + aByteStream next.
	rsaModulus := aByteStream next: rsaModLength.
	rsaExpLength := (aByteStream next bitShift: 8) + aByteStream next.
	rsaExponent := aByteStream next: rsaExpLength</body>

<body package="SSL" selector="writeParametersOn:">writeParametersOn: aByteStream

	| modLength expLength |
	modLength := rsaModulus size.
	expLength := rsaExponent size.
	aByteStream
		nextPut: (modLength bitShift: -8);
		nextPut: (modLength bitAnd: 255);
		nextPutAll: rsaModulus.
	aByteStream
		nextPut: (expLength bitShift: -8);
		nextPut: (expLength bitAnd: 255);
		nextPutAll: rsaExponent</body>
</methods>

<methods>
<class-id>Security.ServerRSAKeyExchangeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="publicKey">publicKey

	^RSAPublicKey
		e: (rsaExponent inject: 0 into: [ :t :b | t * 256 + b ])
		n: (rsaModulus inject: 0 into: [ :t :b | t * 256 + b ])</body>
</methods>

<methods>
<class-id>Security.ServerRSAKeyExchangeMessage</class-id> <category>initialization</category>

<body package="SSL" selector="modulus:exponent:">modulus: modInteger exponent: expInteger

	rsaModulus := modInteger asBigEndianByteArray.
	rsaExponent := expInteger asBigEndianByteArray</body>
</methods>

<methods>
<class-id>Security.ServerRSAKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="modulus:exponent:">modulus: modInteger exponent: expInteger

	^self new modulus: modInteger exponent: expInteger</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>server handshaking</category>

<body package="SSL" selector="acceptHandshake:subjectValidator:">acceptHandshake: aHandshake subjectValidator: aBlock

	id isNil "If we're resuming then I am an old session and already have an id"
		ifTrue: [ subjectValidator := aBlock.
			self acceptNew: aHandshake ]
		ifFalse: [ self acceptResume: aHandshake ]</body>

<body package="SSL" selector="acceptNew:">acceptNew: aHandshake

	| serverKeyMaterial keyMaterial clientKeyMaterial | 
	self
		sendServerHello: aHandshake;
		sendServerKeyExchange: aHandshake;
		receiveClientKeyExchange: aHandshake.
	keyMaterial := aHandshake connection generateKeyMaterialUsing: secret.
	clientKeyMaterial := keyMaterial first.
	serverKeyMaterial := keyMaterial last.
	self
		receiveChangeCipherSpec: aHandshake keyMaterial: clientKeyMaterial;
		receiveFinished: aHandshake forServer: false;
		sendChangeCipherSpec: aHandshake keyMaterial: serverKeyMaterial;
		sendFinished: aHandshake forServer: true</body>

<body package="SSL" selector="acceptResume:">acceptResume: aHandshake

	| serverKeyMaterial keyMaterial clientKeyMaterial |
	self sendServerHello: aHandshake.
	keyMaterial := aHandshake connection generateKeyMaterialUsing: secret.
	clientKeyMaterial := keyMaterial first.
	serverKeyMaterial := keyMaterial last.
	self
		sendChangeCipherSpec: aHandshake keyMaterial: serverKeyMaterial;
		sendFinished: aHandshake forServer: true;
		receiveChangeCipherSpec: aHandshake keyMaterial: clientKeyMaterial;
		receiveFinished: aHandshake forServer: false</body>

<body package="SSL" selector="processClientHello:using:">processClientHello: aMsg using: aHandshake

	aHandshake clientHello: aMsg.
	(aMsg majorVersion = self majorVersion "and: [ aMsg minorVersion = self minorVersion ]") ifFalse: [
		SSLHandshakeFailure new
			messageText: (#IncompatibleProtocolVersion &lt;&lt; #security &gt;&gt; 'Incompatible protocol version');
			parameter: aMsg;
			sendIn: aHandshake ].
	aHandshake connection setClientRandom: aMsg randomValue.
	^aMsg sessionId isNil
		ifTrue: [ self ]
		ifFalse: [ | session |
			session := context sessionForId: aMsg sessionId.
			session isNil
				ifTrue: [ self ]
				ifFalse: [ session ] ]</body>

<body package="SSL" selector="receiveClientHello:">receiveClientHello: aHandshake

	| msg |
	msg := aHandshake next.
	(msg isKindOf: ClientHelloMessage) ifFalse: [
		aHandshake unexpectedMessage: msg ].
	^self processClientHello: msg using: aHandshake</body>

<body package="SSL" selector="receiveClientKeyExchange:">receiveClientKeyExchange: aHandshake 

	cipherSuite receiveClientKeyExchange: aHandshake</body>

<body package="SSL" selector="sendServerHello:">sendServerHello: aHandshake

	| msg r |
	id isNil ifTrue: [
		(cipherSuite := self pickCipherSuiteFrom: aHandshake cipherSuites) isNil ifTrue: [
			SSLHandshakeFailure new
				messageText: (#IncompatibleCipherSuites &lt;&lt; #security &gt;&gt; 'Incompatible cipher suites');
				parameter: aHandshake cipherSuites;
				sendIn: aHandshake ].
		self beResumable ].
	r := self generateRandom.
	aHandshake connection
		setServerRandom: r;
		pendingReadCipherSpec: cipherSuite cipherSpecClone;
		pendingWriteCipherSpec: cipherSuite cipherSpecClone.
	msg := ServerHelloMessage
			major: self majorVersion
			minor: self minorVersion
			random: r
			session: id
			suite: cipherSuite.
	aHandshake
		serverHello: msg;
		nextPut: msg</body>

<body package="SSL" selector="sendServerKeyExchange:">sendServerKeyExchange: aHandshake

	| msg |
	cipherSuite sendServerKeyExchange: aHandshake.
	(aHandshake serverAuthenticates and: [ self shouldPeerAuthenticate ]) ifTrue: [
		msg := CertificateRequestMessage
				certificateTypes: context supportedCertificateTypes
				authorityNames: context recognizedAuthorityNames.
		aHandshake certificateRequest: msg; nextPut: msg ].
	msg := ServerHelloDoneMessage new.
	aHandshake
		serverHelloDone: msg;
		nextPut: msg;
		commit</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>client handshaking</category>

<body package="SSL" selector="connectHandshake:subjectValidator:">connectHandshake: aHandshake subjectValidator: aBlock

	(secret isNil "If we're resuming then I am an old session and I already have a secret"
			or: [ id isNil ]) " and my id has to be accepted by the server"
		ifTrue: [ subjectValidator := aBlock.
			 self connectNew: aHandshake ]
		ifFalse: [ self connectResume: aHandshake ]</body>

<body package="SSL" selector="connectNew:">connectNew: aHandshake 
	| serverKeyMaterial keyMaterial clientKeyMaterial |
	self
		receiveServerKeyExchange: aHandshake;
		sendClientKeyExchange: aHandshake.
	keyMaterial := aHandshake connection generateKeyMaterialUsing: secret.
	clientKeyMaterial := keyMaterial first.
	serverKeyMaterial := keyMaterial last.
	self
		sendChangeCipherSpec: aHandshake keyMaterial: clientKeyMaterial;
		sendFinished: aHandshake forServer: false;
		receiveChangeCipherSpec: aHandshake keyMaterial: serverKeyMaterial;
		receiveFinished: aHandshake forServer: true</body>

<body package="SSL" selector="connectResume:">connectResume: aHandshake

	| serverKeyMaterial keyMaterial clientKeyMaterial |
	keyMaterial := aHandshake connection generateKeyMaterialUsing: secret.
	clientKeyMaterial := keyMaterial first.
	serverKeyMaterial := keyMaterial last.
	self
		receiveChangeCipherSpec: aHandshake keyMaterial: serverKeyMaterial;
		receiveFinished: aHandshake forServer: true;
		sendChangeCipherSpec: aHandshake keyMaterial: clientKeyMaterial;
		sendFinished: aHandshake forServer: false</body>

<body package="SSL" selector="receiveServerHello:">receiveServerHello: aHandshake

	| msg session |
	msg := aHandshake  next.
	(msg isKindOf: ServerHelloMessage) ifFalse: [
		aHandshake  unexpectedMessage: msg ].
	aHandshake serverHello: msg.
	"SSL 2.0 fall back would go here, if we supported it.
	For now let's just refuse talking anything else but SSL 3.0"
	(msg majorVersion = self majorVersion and: [ msg minorVersion = self minorVersion ]) ifFalse: [
		SSLHandshakeFailure new
			messageText: (#IncompatibleProtocolVersion &lt;&lt; #security &gt;&gt; 'Incompatible protocol version');
			parameter: msg;
			sendIn: aHandshake ].
	aHandshake connection setServerRandom: msg randomValue.
	session := (id notNil and: [ id = msg sessionId ])
		ifTrue: [ "If the server confirms my session id then we are resuming"
			self ]
		ifFalse: [ "Let's check that the cipherSuite is one of the offered suites"
			(aHandshake cipherSuites includes: msg cipherSuite) ifFalse: [
				SSLHandshakeFailure new
					messageText: (#InvalidCipherSuite &lt;&lt; #security &gt;&gt; 'Invalid cipher suite');
					parameter: msg;
					sendIn: aHandshake ].
			id isNil
				ifTrue: [ id := msg sessionId.
					cipherSuite := msg cipherSuite.
					secret := nil.
					self ]
				ifFalse: [ (SSLSession newIn: context)
						setId: msg sessionId;
						setCipherSuite: msg cipherSuite;
						beClient;
						yourself ] ].
	aHandshake connection
		pendingReadCipherSpec: session cipherSuite cipherSpecClone;
		pendingWriteCipherSpec: session cipherSuite cipherSpecClone.
	^session</body>

<body package="SSL" selector="receiveServerKeyExchange:">receiveServerKeyExchange: aHandshake

	| msg |
	msg := cipherSuite receiveServerKeyExchange: aHandshake.
	(aHandshake serverAuthenticates and: [ msg isKindOf: CertificateRequestMessage ]) ifTrue: [
		aHandshake certificateRequest: msg.
		msg := aHandshake next ].
	(msg isKindOf: ServerHelloDoneMessage)
		ifTrue: [ aHandshake serverHelloDone: msg ]
		ifFalse: [ aHandshake unexpectedMessage: msg ]</body>

<body package="SSL" selector="sendClientHello:">sendClientHello: aHandshake

	| msg r css |
	r := self generateRandom.
	aHandshake connection setClientRandom: r.
	css := context ciphers.
	msg := ClientHelloMessage
			major: self majorVersion
			minor: self minorVersion
			random: r
			session: id
			suites: css.
	aHandshake
		clientHello: msg;
		nextPut: msg;
		commit.
	^css</body>

<body package="SSL" selector="sendClientKeyExchange:">sendClientKeyExchange: aHandshake 

	cipherSuite sendClientKeyExchange: aHandshake.
	aHandshake commit</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>accessing</category>

<body package="SSL" selector="beClient">beClient

	isServer := false</body>

<body package="SSL" selector="beNonResumable">beNonResumable

	isServer ifTrue: [context disallowToResume: self].
	id := nil</body>

<body package="SSL" selector="beResumable">beResumable

	isServer ifTrue: [
		id := context newIdForSession: self ]</body>

<body package="SSL" selector="beServer">beServer

	isServer := true</body>

<body package="SSL" selector="cipherSuite">cipherSuite

	^cipherSuite</body>

<body package="SSL" selector="context">context

	^context</body>

<body package="SSL" selector="id">id

	^id</body>

<body package="SSL" selector="isResumable">isResumable

	^id notNil and: [ isServer not or: [ (context sessionForId: id) = self] ]</body>

<body package="SSL" selector="isServer">isServer

	^isServer</body>

<body package="SSL" selector="majorVersion">majorVersion

	^majorVersion isNil
		ifTrue: [context majorVersion]
		ifFalse: [majorVersion]</body>

<body package="SSL" selector="masterSecret">masterSecret

	^secret</body>

<body package="SSL" selector="minorVersion">minorVersion

	^minorVersion isNil
		ifTrue: [context minorVersion]
		ifFalse: [minorVersion]</body>

<body package="SSL" selector="peerCertificate">peerCertificate

	^peerCertificate</body>

<body package="SSL" selector="random">random

	^context random</body>

<body package="SSL" selector="shouldPeerAuthenticate">shouldPeerAuthenticate

	^subjectValidator notNil</body>

<body package="SSL" selector="subjectValidator">subjectValidator

	^subjectValidator</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>services</category>

<body package="SSL" selector="accept:subjectValidator:">accept: aConnection subjectValidator: aBlock

	| handshake session |
	self beServer.
	handshake := SSLHandshake connection: aConnection.
	"InputState default shiftDown ifTrue: [self halt]."
	[	session := self receiveClientHello: handshake.
		session acceptHandshake: handshake subjectValidator: aBlock
	] on: SSLException do: [ :ex | session notNil ifTrue: [ session beNonResumable ]. ex pass ].
	^session</body>

<body package="SSL" selector="connect:subjectValidator:">connect: aConnection subjectValidator: aBlock

	| session handshake |
	self beClient.
	handshake := SSLHandshake connection: aConnection.
	"InputState default ctrlDown ifTrue: [self halt]."
	self sendClientHello: handshake.
	[	session := self receiveServerHello: handshake.
		session ~~ self ifTrue: [
			aConnection resumptionFallbackSession: session ].
		session connectHandshake: handshake subjectValidator: aBlock
	] on: SSLException do: [ :ex |
		session notNil ifTrue: [ session beNonResumable ].
		ex pass ]</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>initialization</category>

<body package="SSL" selector="initializeIn:">initializeIn: aContext

	context := aContext</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>private</category>

<body package="SSL" selector="clientReconnect:">clientReconnect: aConnection

	self connect: aConnection subjectValidator: subjectValidator</body>

<body package="SSL" selector="currentUnixTimeT">currentUnixTimeT
"Return current time and date in standard Unix 32-bit format. It is defined as time_t an unsigned 32-bit integer representing count of seconds since January 1, 1970."

	"VW secondClock counts from 1901 so we need to subtract the seconds between then and 1970
	The value is computed as (Date newDay: 1 year: 1970) asSeconds -&gt; 2177452800"
	^Time secondClock - 2177452800</body>

<body package="SSL" selector="finishHandshakeDigest:">finishHandshakeDigest: aHash
"This computes the handshake digest used by CertificateVerify message
as prescribed by sections 7.6.8 of SSL 3.0 Spec:
 	Hash(master_secret + pad_2 + Hash(handshake_messages + master_secret + pad_1))

	aHash &lt;Hash&gt; a running hash already updated with relevant handshake messages
	^&lt;ByteArray&gt; the digest value"

	| digest |
	aHash updateWith: secret;
		updateWith: aHash sslPadding1.
	digest := aHash digest.
	^aHash reset;
		updateWith: secret;
		updateWith: aHash sslPadding2;
		updateWith: digest;
		digest</body>

<body package="SSL" selector="finishHandshakeDigest:asServer:">finishHandshakeDigest: aHash asServer: asServer
"This computes the handshake digest used by Finished messages
as prescribed by section  7.6.9 of SSL 3.0 Spec.
	enum { client(0x434C4E54), server(0x53525652) } Sender;
	Hash(master_secret + pad2 + Hash(handshake_messages + Sender + master_secret + pad1));
	
	aHash &lt;Hash&gt; a running hash already updated with relevant handshake messages
	asServer &lt;Boolean&gt; indicates if the digest is for server Finished, or client Finished
	^&lt;ByteArray&gt; the digest value"

	aHash updateWith: (
		asServer
			ifTrue: [ #[16r53 16r52 16r56 16r52] ]
			ifFalse: [ #[16r43 16r4c 16r4e 16r54] ] ).
	^self finishHandshakeDigest: aHash</body>

<body package="SSL" selector="generateMasterSecretFrom:using:">generateMasterSecretFrom: aPreMasterSecret using: aConnection
"The algorithm for generation of master secret as prescribed in SSL 3.0 Spec/Chapter 8.1."

	^secret := (aConnection masterSecretStreamFrom: aPreMasterSecret) next: 48</body>

<body package="SSL" selector="generateRandom">generateRandom
"Random is a 32 byte sequence defined in section 7.6.1.2 of the SSL 3.0 Spec as follows

	struct {
		uint32 gmt_unix_time;		/*Current time and date in standard Unix 32-bit format*/
		opaque random_bytes[28];	/*securely-generated random bytes*/
	} Random

This can be used for both client and server random generation"

	| random randomStream time |
	random := ByteArray new: 32.
	randomStream := self random byteStream.
	"gmt_unix_time is aparently 'time_t', an unsigned 32-bit count of seconds since January 1, 1970."
	time := self currentUnixTimeT.
	4 to: 1 by: -1 do: [ :i |
		random at: i put: time \\ 256.
		time := time bitShift: -8 ].
	"generate the random rest"
	4 to: 32 do: [ :i |
		random at: i put: randomStream next ].
	^random</body>

<body package="SSL" selector="MD5">MD5

	^MD5 new</body>

<body package="SSL" selector="peerCertificate:">peerCertificate: aCertificateChain

	peerCertificate := aCertificateChain</body>

<body package="SSL" selector="pickCipherSuiteFrom:">pickCipherSuiteFrom: cipherSuites
"Let's emphasise client's preferences. The spec says client specifies suites in order of preference and server chooses.
So for client's order to have any bearing we have to iterate over client list and pick first one that is acceptable. "

	^cipherSuites detect: [ :cs | context ciphers includes: cs ] ifNone: [ nil ]</body>

<body package="SSL" selector="serverReconnect:hello:">serverReconnect: aConnection hello: aHelloMessage

	| handshake session helloStream |
	handshake := SSLHandshake connection: aConnection.
	"Have to allow the handshake to digest the hello that was already received"
	helloStream := ReadWriteStream on: (ByteArray new: 30).
	aHelloMessage writeOn: helloStream in: aConnection.
	handshake digestStream: helloStream from: 0.
	"InputState default shiftDown ifTrue: [self halt]."
	[	session := self processClientHello: aHelloMessage using: handshake.
		session acceptHandshake: handshake subjectValidator: subjectValidator.
	] on: SSLException do: [ :ex | session notNil ifTrue: [ session beNonResumable ]. ex pass ].
	^session</body>

<body package="SSL" selector="setCipherSuite:">setCipherSuite: aCipherSuite

	cipherSuite := aCipherSuite</body>

<body package="SSL" selector="setId:">setId: anId

	id := anId</body>

<body package="SSL" selector="SHA">SHA

	^SHA new</body>
</methods>

<methods>
<class-id>Security.SSLSession</class-id> <category>handshaking</category>

<body package="SSL" selector="receiveChangeCipherSpec:keyMaterial:">receiveChangeCipherSpec: aHandshake keyMaterial: keyMaterial

	| msg |
	msg := aHandshake next.
	(msg isKindOf: ChangeCipherSpecMessage) ifFalse: [
		aHandshake unexpectedMessage: msg ].
	aHandshake connection changeReadCipherSpec: keyMaterial</body>

<body package="SSL" selector="receiveFinished:forServer:">receiveFinished: aHandshake forServer: aBoolean

	| msg md5Hash shaHash |
	"Compute the digest before getting the Finished record,
	otherwise the message digest will be off"
	md5Hash := self finishHandshakeDigest: aHandshake md5 copy asServer: aBoolean.
	shaHash := self finishHandshakeDigest: aHandshake sha copy asServer: aBoolean.
	msg := aHandshake next.
	(msg isKindOf: FinishedMessage) ifFalse: [ aHandshake unexpectedMessage: msg ].
	(md5Hash = msg md5Hash and: [ shaHash = msg shaHash ]) ifFalse: [
		SSLHandshakeFailure new
			messageText: (#FinishedHashMismatch &lt;&lt; #security &gt;&gt; 'Finished hash mismatch');
			parameter: msg;
			sendIn: aHandshake ].
	aHandshake finished: msg.</body>

<body package="SSL" selector="sendChangeCipherSpec:keyMaterial:">sendChangeCipherSpec: aHandshake keyMaterial: keyMaterial

	aHandshake nextPut: ChangeCipherSpecMessage new; commit.
	aHandshake connection changeWriteCipherSpec: keyMaterial</body>

<body package="SSL" selector="sendFinished:forServer:">sendFinished: aHandshake forServer: aBoolean

	| msg |
	msg := FinishedMessage
			md5Hash: (
				self	finishHandshakeDigest: aHandshake md5 copy
					asServer: aBoolean)
			shaHash: (
				self	finishHandshakeDigest: aHandshake sha copy
					asServer: aBoolean).
	aHandshake
		finished: msg;
		nextPut: msg;
		commit</body>

<body package="SSL" selector="validateCertificateChain:for:">validateCertificateChain: aCertificateChain for: aHandshake

	self shouldPeerAuthenticate ifTrue: [
		"Check Subject"
		(subjectValidator value: aCertificateChain first subject) ifFalse: [
			SSLBadCertificate new
				messageText: (#SubjectValidationFailed &lt;&lt; #security &gt;&gt; 'Certificate Subject Failed Validation !');
				parameter: aCertificateChain;
				sendIn: aHandshake ].
		"Check Expiration"
		aCertificateChain first isValid ifFalse: [
			SSLCertificateExpired new
				messageText: (#CurrentlyNotValid &lt;&lt; #security &gt;&gt; 'Present time is not within certificate validity period !');
				parameter: aCertificateChain;
				sendIn: aHandshake ].
		"Check Valididty"
		(context isKnownValidCertificate: aCertificateChain first) ifFalse: [
			context validateCertificateChain: aCertificateChain for: aHandshake ] ].
	peerCertificate := aCertificateChain.</body>
</methods>

<methods>
<class-id>Security.SSLSession class</class-id> <category>instance creation</category>

<body package="SSL" selector="newIn:">newIn: aContext

	^self new initializeIn: aContext</body>
</methods>

<methods>
<class-id>Security.SSLEncodedStreamConstructor</class-id> <category>streams</category>

<body package="SSL" selector="appendStream">appendStream

	^self addEncodingTo: (dataRepository dataWriteStream)</body>

<body package="SSL" selector="newReadWriteStream">newReadWriteStream

	^self notImplemented</body>

<body package="SSL" selector="readAppendStream">readAppendStream

	^self addEncodingTo: (
		InputOutputStream
			in: dataRepository dataReadStream
			out: dataRepository dataWriteStream)</body>

<body package="SSL" selector="readStream">readStream

	^self addEncodingTo: (dataRepository dataReadStream)</body>

<body package="SSL" selector="readWriteStream">readWriteStream

	^self notImplemented</body>

<body package="SSL" selector="writeStream">writeStream

	^self notImplemented</body>
</methods>

<methods>
<class-id>Security.CertificateVerifyMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length vectorLength |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	"It's actually just the TLS spec that states it clearly that digitally-signed element is encoded as
	an opaque variable vector &lt;0..2^16-1&gt;, which in turn should be prefixed by its length.
	See RFC2246 section 4.7 'Cryptographic attributes' and 4.3 'Vectors'"
	vectorLength := (aByteStream next bitShift: 8) bitOr: aByteStream next.
	length - vectorLength = 2 ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidSigLength1s2s &lt;&lt; #security &gt;&gt; 'Signature vector length &lt;1s&gt;does not match stated signature length &lt;2s&gt;')
					expandMacrosWith: vectorLength printString
					with: length printString);
			parameter: (Array with: vectorLength with: length);
			raise ].
	signature := aByteStream next: vectorLength.
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| length |
	super writeOn: aByteStream in: aConnection.
	length := signature size.
	self writeByteLength: length + 2 "vector length" on: aByteStream in: aConnection.
	"It's actually just the TLS spec that states it clearly that digitally-signed element is encoded as
	an opaque variable vector &lt;0..2^16-1&gt;, which in turn should be prefixed by its length.
	See RFC2246 section 4.7 'Cryptographic attributes' and 4.3 'Vectors'"
	aByteStream nextPut: ((length bitShift: -8) bitAnd: 255); nextPut: (length bitAnd: 255).
	aByteStream nextPutAll: signature</body>
</methods>

<methods>
<class-id>Security.CertificateVerifyMessage</class-id> <category>initialization</category>

<body package="SSL" selector="signature">signature

	^signature</body>

<body package="SSL" selector="signature:">signature: sigBA

	signature := sigBA</body>
</methods>

<methods>
<class-id>Security.CertificateVerifyMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^15</body>
</methods>

<methods>
<class-id>Security.CertificateVerifyMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>

<body package="SSL" selector="signature:">signature: aByteArray

	^self new signature: aByteArray</body>
</methods>

<methods>
<class-id>Security.HelloRequestMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	length isZero ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidHRLength1s &lt;&lt; #security &gt;&gt; 'Received hello_request with non-zero length &lt;1s&gt;')
					expandMacrosWith: length printString);
			parameter: length;
			raise ].
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	self writeByteLength: 0 on: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.HelloRequestMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^0</body>
</methods>

<methods>
<class-id>Security.HelloRequestMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ClientKeyExchangeMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^16</body>
</methods>

<methods>
<class-id>Security.ClientKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^aConnection cipherSuite keyExchange clientKeyExchangeMessageClass
		readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLCertificateExpired class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^45</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>handshake services</category>

<body package="SSL" selector="certificateVerifyHandshakeDigest">certificateVerifyHandshakeDigest
"This is used for the CertificateVerifyMessage signature"

	^self clientCertificate isRSA
		ifTrue: [ self rsaMessageDigestFor: connection session ]
		ifFalse: [ self dsaMessageDigestFor: connection session ]</body>

<body package="SSL" selector="cipherSuites">cipherSuites

	^clientHello cipherSuites</body>

<body package="SSL" selector="clientAuthenticates">clientAuthenticates

	^clientCertificate notNil</body>

<body package="SSL" selector="compatibleClientCertificate">compatibleClientCertificate

	^self context certificateCompatibleWith: certificateRequest</body>

<body package="SSL" selector="do:">do: aBlock

	self messages do: aBlock</body>

<body package="SSL" selector="generateMasterSecretFrom:">generateMasterSecretFrom: pms

	connection session generateMasterSecretFrom: pms using: connection</body>

<body package="SSL" selector="serverAuthenticates">serverAuthenticates

	^serverCertificate notNil</body>

<body package="SSL" selector="shouldAuthenticateClient">shouldAuthenticateClient

	^certificateRequest notNil</body>

<body package="SSL" selector="signedMessageDigestUsingKey:">signedMessageDigestUsingKey: aPrivateKey
"This is used for the CertificateVerifyMessage signature"

	^self clientCertificate isRSA
		ifTrue: [ self rsaSignedMessageDigestFor: connection session key: aPrivateKey ]
		ifFalse: [ self dsaSignedMessageDigestFor: connection session key: aPrivateKey ]</body>

<body package="SSL" selector="signKeyExchangeMessage:key:">signKeyExchangeMessage: msg key: aPrivateKey
"This is used for the ServerKeyExchange signature"

	serverCertificate notNil ifTrue: [
		serverCertificate isRSA
			ifTrue: [ self rsaSignKeyExchangeMessage: msg key: aPrivateKey ]
			ifFalse: [ self dsaSignKeyExchangeMessage: msg key: aPrivateKey ] ]</body>

<body package="SSL" selector="validateCertificateChain:">validateCertificateChain: aCertificateChain

	^connection session validateCertificateChain: aCertificateChain for: self</body>

<body package="SSL" selector="verifyClientSignature:of:">verifyClientSignature: signature of: digest
"This is used for the CertificateVerifyMessage signature"

	^self clientCertificate isRSA
		ifTrue: [ self rsaVerifyClientSignature: signature of: digest ]
		ifFalse: [ self dsaVerifyClientSignature: signature of: digest ]</body>

<body package="SSL" selector="verifyKeyExchageMessageSignature:">verifyKeyExchageMessageSignature: msg
"This is used for the ServerKeyExchange signature"

	serverCertificate isNil ifTrue: [^true].
	^(serverCertificate isRSA
		ifTrue: [ self rsaVerifyKeyExchageMessageSignature: msg ]
		ifFalse: [ self dsaVerifyKeyExchageMessageSignature: msg ]
	)	ifTrue: [true]
		ifFalse: [SSLHandshakeFailure new
				messageText: (#BadSKESignature &lt;&lt; #security &gt;&gt; 'Bad signature on ServerKeyExchange !');
				parameter: msg;
				sendIn: self]</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>accessing</category>

<body package="SSL" selector="connection">connection

	^connection</body>

<body package="SSL" selector="context">context

	^connection context</body>

<body package="SSL" selector="majorVersion">majorVersion

	^connection session majorVersion</body>

<body package="SSL" selector="md5">md5

	^md5</body>

<body package="SSL" selector="messages">messages

	^OrderedCollection new
		add: clientHello;
		add: serverHello;
		add: serverCertificate;
		add: serverKeyExchange;
		add: certificateRequest;
		add: serverHelloDone;
		add: clientCertificate;
		add: clientKeyExchange;
		add: certificateVerify;
		add: finished;
		reject: [ :e | e isNil ]</body>

<body package="SSL" selector="minorVersion">minorVersion

	^connection session minorVersion</body>

<body package="SSL" selector="random">random

	^connection random</body>

<body package="SSL" selector="sha">sha

	^sha</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>rsa handshake services</category>

<body package="SSL" selector="rsaCheckClientVersionInPremasterSecret:">rsaCheckClientVersionInPremasterSecret: pms
"http://www.ietf.org/rfc/rfc2246.txt, 7.4.7.1. RSA encrypted premaster secret message:
client_version - The latest (newest) version supported by the client. This is used to detect version roll-back attacks. Upon receiving the premaster secret, the server should check that this value matches the value transmitted by the client in the client hello message.

In a version rollback attack the attacker modifies in transit the unprotected client_hello message, carrying the indicator of the highest protocol version supported by the client. By reducing the version number the attacker can force the client and server to negotiate an older (potentially weaker) version of the protocol, even though they are capable of using a more recent one. Since the premaster secret is encrypted, the client can use the version field in it to resubmit the originally provided version number in a way that is hard for the attacker to modify as well. The server should check if the PMS version matches the client_hello version it received.

However, [ Rescorla: SSL &amp; TLS, p.79 ] says that strict checking of the client version can cause compatibility issues as many clients use the negotiated version in the PMS instead of the client_hello one. Accepting that means that we won't be able to detect version rollback when client uses negotiated version in PMS, however we can still detect one when the client properly uses the highest version in PMS. In that case the version in the client_hello would be less than the one in the PMS, so let's check at least that."

	"This should really be strict equivalence of clientHello and PMS versions, however enforcing that can yield to false incompatibilities with some clients.
	So we at least make sure that clientHello isn't smaller than PMS"
	(self clientHello majorVersion &gt; (pms at: 1)
	or: [ self clientHello majorVersion = (pms at: 1) and: [ self clientHello minorVersion &gt;= (pms at: 2)]]
	) ifFalse: [
		SSLHandshakeFailure new
			messageText: (#ClientVersionRollbackAttack &lt;&lt; #security &gt;&gt; 'Version number in the premaster secret is higher than the highest supported version advertised in the client_hello. Version rollback attack!');
			parameter: pms;
			sendIn: self].</body>

<body package="SSL" selector="rsaKeyExchangeMessageDigest:">rsaKeyExchangeMessageDigest: msg
"This is used for the ServerKeyExchange signature"

	| ws size |
	ws := (ByteArray new: 250) readWriteStream.
	ws nextPutAll: clientHello randomValue.
	ws nextPutAll: serverHello randomValue.
	msg writeParametersOn: ws.
	size := ws position.
	^(MD5 byteHashNext: size inStream: (ws reset; yourself)),
	  (SHA byteHashNext: size inStream: (ws reset; yourself))</body>

<body package="SSL" selector="rsaMessageDigestFor:">rsaMessageDigestFor: aSession
"This is used for the CertificateVerifyMessage signature"

	^	(aSession finishHandshakeDigest: self md5 copy),
		(aSession finishHandshakeDigest: self sha copy)</body>

<body package="SSL" selector="rsaSignedMessageDigestFor:key:">rsaSignedMessageDigestFor: aSession key: aPrivateKey
"This is used for the CertificateVerifyMessage signature"

	^RSA new
		privateKey: aPrivateKey;
		sign: (self rsaMessageDigestFor: aSession)</body>

<body package="SSL" selector="rsaSignKeyExchangeMessage:key:">rsaSignKeyExchangeMessage: msg key: aPrivateKey
"This is used for the ServerKeyExchange signature"

	msg signature: (
		RSA new
			privateKey: aPrivateKey;
			sign: (self rsaKeyExchangeMessageDigest: msg))</body>

<body package="SSL" selector="rsaVerifyClientSignature:of:">rsaVerifyClientSignature: signature of: digest
"This is used for the CertificateVerifyMessage signature"

	^RSA new
		publicKey: clientCertificate publicKey;
		verify: signature
		of: digest</body>

<body package="SSL" selector="rsaVerifyKeyExchageMessageSignature:">rsaVerifyKeyExchageMessageSignature: msg 
"This is used for the ServerKeyExchange signature"

	^RSA new
		publicKey: serverCertificate publicKey;
		verify: msg signature
		of: (self rsaKeyExchangeMessageDigest: msg)</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>dsa handshake services</category>

<body package="SSL" selector="dsaKeyExchangeMessageDigest:">dsaKeyExchangeMessageDigest: msg
"This is used for the ServerKeyExchange signature"

	| ws size |
	ws := (ByteArray new: 250) readWriteStream.
	ws nextPutAll: clientHello randomValue.
	ws nextPutAll: serverHello randomValue.
	msg writeParametersOn: ws.
	size := ws position.
	^(SHA byteHashNext: size inStream: (ws reset; yourself))</body>

<body package="SSL" selector="dsaMessageDigestFor:">dsaMessageDigestFor: aSession
"This is used for the CertificateVerifyMessage signature"

	^aSession finishHandshakeDigest: self sha copy</body>

<body package="SSL" selector="dsaSignedMessageDigestFor:key:">dsaSignedMessageDigestFor: aSession key: aPrivateKey
"This is used for the CertificateVerifyMessage signature"

	^(	DSA new
			privateKey: aPrivateKey;
			signDigest: (self dsaMessageDigestFor: aSession)
	) asDERSequence</body>

<body package="SSL" selector="dsaSignKeyExchangeMessage:key:">dsaSignKeyExchangeMessage: msg key: aPrivateKey
"This is used for the ServerKeyExchange signature"

	msg signature: (
		DSA new
			privateKey: aPrivateKey;
			signDigest: (self dsaKeyExchangeMessageDigest: msg)
		) asDERSequence</body>

<body package="SSL" selector="dsaVerifyClientSignature:of:">dsaVerifyClientSignature: signature of: digest
"This is used for the CertificateVerifyMessage signature"

	^DSA new
		publicKey: clientCertificate publicKey;
		verify: (DSASignature fromDERSequence: signature)
		ofDigest: digest</body>

<body package="SSL" selector="dsaVerifyKeyExchageMessageSignature:">dsaVerifyKeyExchageMessageSignature: msg 
"This is used for the ServerKeyExchange signature"

	^DSA new
		publicKey: serverCertificate publicKey;
		verify: (DSASignature fromDERSequence: msg signature)
		ofDigest: (self dsaKeyExchangeMessageDigest: msg)</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>private</category>

<body package="SSL" selector="digestStream:from:">digestStream: aStream from: start
"Update the digests with the contents of aStream from position start up to current position"

	| count |
	count := aStream position - start.
	aStream position: start.
	md5 updateWithNext: count from: aStream.
	aStream position: start.
	sha updateWithNext: count from: aStream.</body>

<body package="SSL" selector="generatePreMasterSecret">generatePreMasterSecret
"The pre_master_secret is described in section 7.6.7.1 of the SSL 3.0 Spec. It is defined as follows

	struct {
		ProtocolVersion client_version;  /* The latest protocol version supported by the client */
		opaque random[46];		/* 46 securely-generated random bytes */
	} PreMasterSecret

The ProtocolVersion is defined in section 7.2.1 of the Spec as

	struct {
		uint8 major, minor
	} ProtocolVersion

which in case of SSL 3.0 means { 3, 0 }"

	| random randomStream |
	random := ByteArray new: 48.
	"set protocol version"
	random at: 1 put: 3.
	random at: 2 put: 0.
	"then generate the random rest"
	randomStream := self random byteStream.
	3 to: 48  do: [ :i | random at: i put: randomStream next ].
	^random</body>

<body package="SSL" selector="unexpectedMessage:">unexpectedMessage: msg
"SSL3.0 Spec: An inappropriate message was received. This alert is always fatal and should never be observed in communication between proper implementations."

	msg isAlert
		ifTrue: [ msg raiseException ]
		ifFalse: [ SSLUnexpectedMessage new
				messageText: (
					(#UnexpectedMessage1s &lt;&lt; #security &gt;&gt; 'Unexpected message &lt;1s&gt;')
						expandMacrosWith: msg printString);
				parameter: msg;
				sendIn: self ]</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>connection services</category>

<body package="SSL" selector="commit">commit

	connection commitStream: writeStream.
	writeStream dump.</body>

<body package="SSL" selector="next">next

	| msg |
	readStream basicAtEnd ifTrue: [ readStream dump ].
	[	[	| start mc |
			start := readStream position.
			mc := readStream fragment messageClass.
			msg := mc readFrom: readStream in: connection.
			msg isHandshake ifTrue: [
				self digestStream: readStream from: start ].
		] 	on: EndOfStreamNotification do: [ :ex |
			SSLHandshakeFailure raiseSignal: (
				#UnexpectedEndOfStream &lt;&lt; #security &gt;&gt; 'Unexpected end of stream !') ]
	] on: SSLError do: [ :ex |
		self sendMessage: ex alertMessage.
		ex pass ].
	connection triggerEvent: #receivingMessage: with: msg.
	^msg</body>

<body package="SSL" selector="nextPut:">nextPut: aMessage

	"Only messages from the same protocol can go into the same record"
	| start |
	(writeStream basicAtEnd not and: [ writeStream fragment protocol ~= aMessage protocol ])
		ifTrue: [ writeStream trimLastRecord ].
	writeStream basicAtEnd ifTrue: [
		writeStream addFragment: (connection newRecordForProtocol: aMessage protocol) ].
	connection triggerEvent: #sendingMessage: with: aMessage.
	start := writeStream position.
	aMessage writeOn: writeStream in: connection.
	aMessage isHandshake ifTrue: [
		self digestStream: writeStream from: start ].
	^aMessage</body>

<body package="SSL" selector="sendMessage:">sendMessage: aMessage
"Send a message outside of the writeStream. Useful for sending Alerts and such"

	connection sendMessage: aMessage</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>initialization</category>

<body package="SSL" selector="initialize:">initialize: aConnection

	connection := aConnection.
	readStream := (FragmentStream onFragment: nil)
					setFragmentProvider: aConnection message: #nextRecordFor:;
					yourself.
	writeStream := (FragmentStream onFragment: nil)
					setFragmentProvider: aConnection message: #nextEmptyRecordFor:;
					yourself.
	sha := SHA new.
	md5 := MD5 new</body>
</methods>

<methods>
<class-id>Security.SSLHandshake</class-id> <category>accessing - messages</category>

<body package="SSL" selector="certificateRequest">certificateRequest

	^certificateRequest</body>

<body package="SSL" selector="certificateRequest:">certificateRequest: msg

	certificateRequest := msg</body>

<body package="SSL" selector="certificateVerify">certificateVerify

	^certificateVerify</body>

<body package="SSL" selector="certificateVerify:">certificateVerify: msg

	certificateVerify := msg</body>

<body package="SSL" selector="clientCertificate">clientCertificate

	^clientCertificate</body>

<body package="SSL" selector="clientCertificate:">clientCertificate: msg

	clientCertificate := msg</body>

<body package="SSL" selector="clientHello">clientHello

	^clientHello</body>

<body package="SSL" selector="clientHello:">clientHello: msg

	clientHello := msg</body>

<body package="SSL" selector="clientKeyExchange">clientKeyExchange

	^clientKeyExchange</body>

<body package="SSL" selector="clientKeyExchange:">clientKeyExchange: msg

	clientKeyExchange := msg</body>

<body package="SSL" selector="finished">finished

	^finished</body>

<body package="SSL" selector="finished:">finished: msg

	finished := msg</body>

<body package="SSL" selector="serverCertificate">serverCertificate

	^serverCertificate</body>

<body package="SSL" selector="serverCertificate:">serverCertificate: msg

	serverCertificate := msg</body>

<body package="SSL" selector="serverHello">serverHello

	^serverHello</body>

<body package="SSL" selector="serverHello:">serverHello: msg

	serverHello := msg</body>

<body package="SSL" selector="serverHelloDone">serverHelloDone

	^serverHelloDone</body>

<body package="SSL" selector="serverHelloDone:">serverHelloDone: msg

	serverHelloDone := msg</body>

<body package="SSL" selector="serverKeyExchange">serverKeyExchange

	^serverKeyExchange</body>

<body package="SSL" selector="serverKeyExchange:">serverKeyExchange: msg

	serverKeyExchange := msg</body>
</methods>

<methods>
<class-id>Security.SSLHandshake class</class-id> <category>instance creation</category>

<body package="SSL" selector="connection:">connection: aConnection

	^self new initialize: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLRecord</class-id> <category>accessing</category>

<body package="SSL" selector="fragment">fragment

	^fragment</body>

<body package="SSL" selector="majorVersion">majorVersion

	^majorVersion</body>

<body package="SSL" selector="minorVersion">minorVersion

	^minorVersion</body>

<body package="SSL" selector="protocol">protocol

	^protocol</body>

<body package="SSL" selector="setFragment:">setFragment: aByteArray

	self setFragment: aByteArray size: aByteArray size</body>

<body package="SSL" selector="setFragment:size:">setFragment: aByteArray size: anInteger

	fragment := aByteArray.
	self setSize: anInteger</body>

<body package="SSL" selector="setSize:">setSize: anInteger

	size := anInteger min: fragment size</body>
</methods>

<methods>
<class-id>Security.SSLRecord</class-id> <category>fragment accessing</category>

<body package="SSL" selector="at:">at: anIndex

	^fragment at: anIndex</body>

<body package="SSL" selector="at:put:">at: anIndex put: aByte

	^fragment at: anIndex put: aByte</body>

<body package="SSL" selector="size">size

	^size</body>

<body package="SSL" selector="species">species

	^fragment species</body>
</methods>

<methods>
<class-id>Security.SSLRecord</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream
		nextPutAll: (#SSLRecord &lt;&lt; #security &gt;&gt; 'SSLRecord') asString;
		nextPut: ${;
		print: self protocol;
		nextPut: $,;
		print: self majorVersion;
		nextPut: $.;
		print: self minorVersion;
		nextPut: $,;
		print: self size;
		nextPutAll: (#ByteSuffix &lt;&lt; #security &gt;&gt; 'B') asString;
		nextPut: $}</body>
</methods>

<methods>
<class-id>Security.SSLRecord</class-id> <category>initialization</category>

<body package="SSL" selector="initializeProtocol:major:minor:">initializeProtocol: protoNr major: majNr minor: minNr

	majorVersion := majNr.
	minorVersion := minNr.
	protocol := protoNr</body>
</methods>

<methods>
<class-id>Security.SSLRecord</class-id> <category>reading/writing</category>

<body package="SSL" selector="headerSize">headerSize

	^self class headerSize</body>

<body package="SSL" selector="messageClass">messageClass

	protocol isNil ifTrue: [^ClientHello20Message].
 	protocol = 20 ifTrue: [^ChangeCipherSpecMessage].
	protocol = 21 ifTrue: [^AlertMessage].
	protocol = 22 ifTrue: [^HandshakeMessage].
	protocol = 23 ifTrue: [
		SSLUnexpectedMessage new
			messageText: (#UnexpectedAppRecord &lt;&lt; #security &gt;&gt; 'Application protocol record not expected');
			parameter: self;
			raise ].
	SSLIllegalParameter new
		messageText: (
			(#InvalidProtocol1s &lt;&lt; #security &gt;&gt; 'Invalid protocol type &lt;1s&gt;')
				expandMacrosWith: protocol printString);
		parameter: protocol;
		raise</body>

<body package="SSL" selector="read20From:in:">read20From: aByteStream in: aConnection
"Read an SSL2.0 record"

	size := aByteStream next.
	self	initializeProtocol: nil
		major: 2
		minor: 0.
	fragment := aByteStream next: size.
	aConnection triggerEvent: #receivingEncryptedBytes:size: with: fragment with: size.
	aConnection triggerEvent: #receivingSignedBytes:size: with: fragment with: size.
	^self</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection
"Read the record in expecting a format defined by SSLCiphertext in section 7.2.3 of the SSL3.0 spec"

	| hashSize decryptedSize signatureBytes |
	(protocol := aByteStream next) = 128 "SSL 2.0"
		ifTrue: [^self read20From: aByteStream in: aConnection ].
	self	initializeProtocol: protocol
		major: aByteStream next
		minor: aByteStream next.
	size := (aByteStream next bitShift: 8) + aByteStream next.
	size &gt; self class maxEncryptedFragmentSize ifTrue: [
		SSLIllegalParameter new
			messageText: (#EncryptedRecordTooLarge &lt;&lt; #security &gt;&gt; 'Encrypted SSL Record fragment size exceeded!');
			parameter: size;
			raise ].
	fragment := aByteStream next: size.
	aConnection triggerEvent: #receivingEncryptedBytes:size: with: fragment with: size.
	decryptedSize := aConnection decrypt: self.
	(hashSize := aConnection readHashSize) = 0
		ifTrue: [ size := decryptedSize.	signatureBytes := nil ]
		ifFalse: [
			size := decryptedSize - hashSize.
			signatureBytes := aConnection readSignatureFor: self.
			1 to: hashSize do: [ :i |
				(signatureBytes at: i) = (fragment at: size + i)
					ifFalse: [SSLBadRecordMAC signalWith: self] ] ].
	size &gt; self class maxFragmentSize ifTrue: [
		SSLIllegalParameter new
			messageText: (#RecordTooLarge &lt;&lt; #security &gt;&gt; 'SSL Record fragment size exceeded!');
			parameter: size;
			raise ].
	aConnection triggerEvent: #receivingSignedBytes:size: with: fragment with: size.
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection
"Write the record out in a fromat defined by SSLCiphertext in section 7.2.3 of the SSL3.0 spec"

	| signatureBytes signedSize |
	signatureBytes := nil.
	signedSize := size + aConnection writeHashSize.
	size = signedSize ifFalse: [
		signatureBytes := aConnection writeSignatureFor: self. 
		fragment replaceFrom: size + 1 to: signedSize with: signatureBytes].
 	aConnection triggerEvent: #sendingSignedBytes:size: with: fragment with: size.
	size := signedSize.
	size := aConnection encrypt: self.
	aConnection triggerEvent: #sendingEncryptedBytes:size: with: fragment with: size.
	aByteStream
		nextPut: protocol;
		nextPut: majorVersion;
		nextPut: minorVersion;
		nextPut: (size bitShift: -8);
		nextPut: (size bitAnd: 16rFF);
		next: size putAll: fragment startingAt: 1</body>
</methods>

<methods>
<class-id>Security.SSLRecord class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLRecord class</class-id> <category>constants</category>

<body package="SSL" selector="headerSize">headerSize

	^5</body>

<body package="SSL" selector="maxEncryptedFragmentSize">maxEncryptedFragmentSize
"Section 5.2.3 'Record payload protection and the CipherSpec' in the SSL 3.02 spec:
     struct {
         ContentType type;
         ProtocolVersion version;
         uint16 length;
         select (CipherSpec.cipher_type) {
             case stream: GenericStreamCipher;
             case block: GenericBlockCipher;
         } fragment;
     } SSLCiphertext;
length = The length (in bytes) of the following SSLCiphertext.fragment. The length may not exceed 2^14 + 2048."

	"(2 raisedTo: 14) + 2048"
	^18432</body>

<body package="SSL" selector="maxFragmentSize">maxFragmentSize
"Section 5.2.1 'Fragmentation' of SSL 3.02 Spec:          
... The record layer fragments information blocks into SSLPlaintext records of 2^14 bytes or less. ..."
	^16384</body>
</methods>

<methods>
<class-id>Security.SSLIllegalParameter class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^47</body>
</methods>

<methods>
<class-id>Security.SSLNoCertificate class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^41</body>
</methods>

<methods>
<class-id>Security.HelloMessage</class-id> <category>accessing</category>

<body package="SSL" selector="majorVersion">majorVersion

	^majorVersion</body>

<body package="SSL" selector="minorVersion">minorVersion

	^minorVersion</body>

<body package="SSL" selector="randomValue">randomValue

	^randomValue</body>

<body package="SSL" selector="sessionId">sessionId

	^sessionId</body>
</methods>

<methods>
<class-id>Security.HelloMessage</class-id> <category>initialization</category>

<body package="SSL" selector="major:minor:random:session:">major: majVer minor: minVer random: ba session: id

	majorVersion := majVer.
	minorVersion := minVer.
	randomValue := ba.
	sessionId := id</body>
</methods>

<methods>
<class-id>Security.HelloMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| sessionIdLength length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	majorVersion := aByteStream next.
	minorVersion := aByteStream next.
	randomValue := aByteStream next: 32.
	sessionIdLength := aByteStream next.
	sessionId := sessionIdLength = 0
		ifTrue: [nil]
		ifFalse: [aByteStream next: sessionIdLength].
	^length - 35 "version(2) + random(32) + idLength(1)" - sessionIdLength</body>

<body package="SSL" selector="writeOn:in:lengthOffset:">writeOn: aByteStream in: aConnection lengthOffset: offset

	| ba length |
	ba := sessionId isNil ifTrue: [ #[] ] ifFalse: [ sessionId ].
	length := 35 "version(2)+random(32)+session length(1)" + ba size.
	self writeByteLength: length + offset on: aByteStream in: aConnection.
	aByteStream
		nextPut: majorVersion;
		nextPut: minorVersion;
		nextPutAll: randomValue;
		nextPut: ba size;
		nextPutAll: ba</body>
</methods>

<methods>
<class-id>Security.HelloMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLBadRecordMAC class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^20</body>
</methods>

<methods>
<class-id>Security.SSLUnsupportedCertificate class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^43</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>private</category>

<body package="SSL" selector="raiseException">raiseException

	| exceptionClass |
	exceptionClass := self class codeToExceptionMap
					at: descriptionCode ifAbsent: [ SSLError ].
	exceptionClass new
		messageText: description;
		parameter: self;
		raise</body>

<body package="SSL" selector="setDescription:">setDescription: aSymbol

	description := aSymbol</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>testing</category>

<body package="SSL" selector="isAlert">isAlert

	^true</body>

<body package="SSL" selector="isFatal">isFatal

	^severityCode = 2</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>accessing</category>

<body package="SSL" selector="description">description

	^description</body>

<body package="SSL" selector="descriptionCode">descriptionCode

	^descriptionCode</body>

<body package="SSL" selector="protocol">protocol

	^21</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>initialization</category>

<body package="SSL" selector="initializeSeverityCode:descriptionCode:">initializeSeverityCode: aSeverityByte descriptionCode: aDescriptionByte

	severityCode := aSeverityByte.
	descriptionCode := aDescriptionByte</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	aByteStream
		nextPut: severityCode;
		nextPut: descriptionCode</body>
</methods>

<methods>
<class-id>Security.AlertMessage</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream
		nextPutAll: (
			self isFatal
				ifTrue: [#FatalAlert &lt;&lt; #security &gt;&gt; 'FatalAlert']
				ifFalse: [#Warning &lt;&lt; #security &gt;&gt; 'Warning']
			) asString;
		nextPut: $[;
		nextPutAll: self description;
		nextPut: $]</body>
</methods>

<methods>
<class-id>Security.AlertMessage class</class-id> <category>alert messages</category>

<body package="SSL" selector="bad_certificate">bad_certificate
"SSL3.0 Spec: A certificate was corrupt, contained signatures that did not verify correctly, etc."

	^CodeToMessageMap
		at: 42
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 42 ]</body>

<body package="SSL" selector="bad_record_mac">bad_record_mac
"SSL3.0Spec: This alert is returned if a record is received with an incorrect MAC.  This message is always fatal."

	^CodeToMessageMap
		at: 20
		ifAbsent: [ self newSeverityCode: 2 descriptionCode: 20 ]</body>

<body package="SSL" selector="certificate_expired">certificate_expired
"SSL3.0 Spec: A certificate has expired or is not currently valid."

	^CodeToMessageMap
		at: 45
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 45 ]</body>

<body package="SSL" selector="certificate_revoked">certificate_revoked
"SSL3.0 Spec: A certificate was revoked by its signer."

	^CodeToMessageMap
		at: 44
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 44 ]</body>

<body package="SSL" selector="certificate_unknown">certificate_unknown
"SSL3.0 Spec: Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable."

	^CodeToMessageMap
		at: 46
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 46 ]</body>

<body package="SSL" selector="close_notify">close_notify
"SSL3.0Spec: This message notifies the recipient that the sender will not send any more messages on this connection.  The session becomes unresumable if any connection is terminated without proper close_notify messages with level equal to warning."

	^CodeToMessageMap
		at: 0
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 0 ]</body>

<body package="SSL" selector="decompression_failure">decompression_failure
"SSL3.0 Spec: The decompression function received improper input (e.g. data that would expand to excessive length).  This message is always fatal."

	^CodeToMessageMap
		at: 30
		ifAbsent: [ self newSeverityCode: 2 descriptionCode: 30 ]</body>

<body package="SSL" selector="handshake_failure">handshake_failure
"SSL3.0 Spec: Reception of a handshake_failure alert message indicates that the sender was unable to negotiate an acceptable set of security parameters given the options available. This is a fatal error."

	^CodeToMessageMap
		at: 40
		ifAbsent: [ self newSeverityCode: 2 descriptionCode: 40 ]</body>

<body package="SSL" selector="illegal_parameter">illegal_parameter
"SSL3.0Spec: A field in the handshake was out of range or inconsistent with other fields.  This is always fatal."

	^CodeToMessageMap
		at: 47
		ifAbsent: [ self newSeverityCode: 2 descriptionCode: 47 ]</body>

<body package="SSL" selector="no_certificate">no_certificate
"SSL3.0Spec: A no_certificate alert message may be sent in response to a certification request if no appropriate certificate is available."

	^CodeToMessageMap
		at: 41
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 41 ]</body>

<body package="SSL" selector="unexpected_message">unexpected_message
"SSL3.0 Spec: An inappropriate message was received. This alert is always fatal and should never be observed in communication between proper implementations."

	^CodeToMessageMap
		at: 10
		ifAbsent: [ self newSeverityCode: 2 descriptionCode: 10 ]</body>

<body package="SSL" selector="unsupported_certificate">unsupported_certificate
"SSL3.0 Spec: A certificate was of an unsupported type."

	^CodeToMessageMap
		at: 43
		ifAbsent: [ self newSeverityCode: 1 descriptionCode: 43 ]</body>
</methods>

<methods>
<class-id>Security.AlertMessage class</class-id> <category>reading/writing</category>

<body package="SSL" selector="codeToExceptionMap">codeToExceptionMap

	CodeToExceptionMap isNil ifTrue: [self rebuildCodeToExceptionMap].
	^CodeToExceptionMap</body>

<body package="SSL" selector="codeToMessageMap">codeToMessageMap

	CodeToMessageMap isNil ifTrue: [self rebuildCodeToMessageMap].
	^CodeToMessageMap</body>

<body package="SSL" selector="newSeverityCode:descriptionCode:">newSeverityCode: aSeverityByte descriptionCode: aDescriptionByte

	^self new initializeSeverityCode: aSeverityByte descriptionCode: aDescriptionByte</body>

<body package="SSL" selector="rebuildCodeToExceptionMap">rebuildCodeToExceptionMap
"(((self rebuildCodeToExceptionMap)))"

	CodeToExceptionMap := IdentityDictionary new.
	SSLException allSubclassesDo: [ :class |
		(class class includesSelector: #alertCode) ifTrue: [
			CodeToExceptionMap at: class alertCode put: class ]].
	^CodeToExceptionMap</body>

<body package="SSL" selector="rebuildCodeToMessageMap">rebuildCodeToMessageMap
"(((self rebuildCodeToMessageMap)))"

	CodeToMessageMap := IdentityDictionary new.
	(self class organization listAtCategoryNamed: #'alert messages')
		do: [ :selector || message |
			message := (self perform: selector) setDescription: selector; yourself.
			CodeToMessageMap at: message descriptionCode put: message ].
	^CodeToMessageMap</body>
</methods>

<methods>
<class-id>Security.AlertMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="code:">code: anInteger

	^self codeToMessageMap at: anInteger ifAbsent: [nil]</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| severityCode descriptionCode |
	severityCode := aByteStream next.
	(1 = severityCode or: [2 = severityCode]) ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidAlertSeverity1s &lt;&lt; #security &gt;&gt; 'Received an Alert with unknown severity &lt;1s&gt;')
					expandMacrosWith: severityCode printString);
			parameter: severityCode;
			raise ].
	descriptionCode := aByteStream next.
	^self codeToMessageMap at: descriptionCode ifAbsent: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidAlertCode1s &lt;&lt; #security &gt;&gt; 'Received an Alert with unknown description &lt;1s&gt;')
					expandMacrosWith: descriptionCode printString);
			parameter: descriptionCode;
			raise ].</body>
</methods>

<methods>
<class-id>Security.InputOutputStream</class-id> <category>accessing</category>

<body package="SSL" selector="basicAtEnd">basicAtEnd

	^in basicAtEnd</body>

<body package="SSL" selector="commit">commit

	^out commit</body>

<body package="SSL" selector="contents">contents

	^in contents</body>

<body package="SSL" selector="flush">flush

	^out flush</body>

<body package="SSL" selector="in">in

	^in</body>

<body package="SSL" selector="next">next

	^in next</body>

<body package="SSL" selector="nextPut:">nextPut: anObject

	^out nextPut: anObject</body>

<body package="SSL" selector="out">out

	^out</body>

<body package="SSL" selector="position">position

	^in position</body>

<body package="SSL" selector="position:">position: anInteger

	^in position: anInteger</body>
</methods>

<methods>
<class-id>Security.InputOutputStream</class-id> <category>private</category>

<body package="SSL" selector="contentsSpecies">contentsSpecies

	^in contentsSpecies</body>

<body package="SSL" selector="in:out:">in: inStream out: outStream

	in := inStream.
	out := outStream.</body>
</methods>

<methods>
<class-id>Security.InputOutputStream</class-id> <category>testing</category>

<body package="SSL" selector="atEnd">atEnd

	^in atEnd</body>

<body package="SSL" selector="isReadable">isReadable

	^true</body>

<body package="SSL" selector="isWritable">isWritable

	^true</body>
</methods>

<methods>
<class-id>Security.InputOutputStream</class-id> <category>status</category>

<body package="SSL" selector="binary">binary</body>

<body package="SSL" selector="close">close

	out close.
	in close.</body>
</methods>

<methods>
<class-id>Security.InputOutputStream</class-id> <category>As yet unclassified</category>

<body package="SSL" selector="skip:">skip: arg1

	^in skip: arg1</body>
</methods>

<methods>
<class-id>Security.InputOutputStream class</class-id> <category>instance creation</category>

<body package="SSL" selector="in:out:">in: inStream out: outStream

	^self basicNew in: inStream out: outStream</body>

<body package="SSL" selector="on:">on: aCollection

	self error: (#IOSCreationRestricted &lt;&lt; #security &gt;&gt; 'Has to be created with 2 shared streams !')</body>

<body package="SSL" selector="with:">with: aCollection

	self error: (#IOSCreationRestricted &lt;&lt; #security &gt;&gt; 'Has to be created with 2 shared streams !')</body>
</methods>

<methods>
<class-id>Security.SSLHandshakeFailure class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^40</body>
</methods>

<methods>
<class-id>Security.SSLUnexpectedMessage class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^10</body>
</methods>

<methods>
<class-id>Security.ClientRSAKeyExchangeMessage</class-id> <category>initialization</category>

<body package="SSL" selector="encryptedPremasterSecret:">encryptedPremasterSecret: aBA

	encryptedPremasterSecret := aBA</body>
</methods>

<methods>
<class-id>Security.ClientRSAKeyExchangeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	encryptedPremasterSecret := aByteStream next: length</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| length |
	super writeOn: aByteStream in: aConnection.
	length := encryptedPremasterSecret size.
	self writeByteLength: length on: aByteStream in: aConnection.
	aByteStream nextPutAll: encryptedPremasterSecret.</body>
</methods>

<methods>
<class-id>Security.ClientRSAKeyExchangeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="preMasterSecretUsingPrivateKey:">preMasterSecretUsingPrivateKey: anRSAPrivateKey

	^RSA new
		privateKey: anRSAPrivateKey;
		decrypt: encryptedPremasterSecret</body>
</methods>

<methods>
<class-id>Security.ClientRSAKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="decryptedPremasterSecret:usingPublicKey:">decryptedPremasterSecret: aBA usingPublicKey: aPublicKey

	^self encryptedPremasterSecret: (
		RSA new
			publicKey: aPublicKey;
			encrypt: aBA)</body>

<body package="SSL" selector="encryptedPremasterSecret:">encryptedPremasterSecret: aBA

	^self new encryptedPremasterSecret: aBA</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ServerHelloDoneMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	length isZero ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidSHDLength1s &lt;&lt; #security &gt;&gt; 'Received server_hello_done with non-zero length &lt;1s&gt;')
					expandMacrosWith: length printString);
			parameter: length;
			raise ].
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	self writeByteLength: 0 on: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ServerHelloDoneMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^14</body>
</methods>

<methods>
<class-id>Security.ServerHelloDoneMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.ClientDHKeyExchangeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	length isZero ifFalse: [ | vectorLength |
		vectorLength := (aByteStream next bitShift: 8) + aByteStream next.
		length - vectorLength = 2 ifFalse: [
			SSLIllegalParameter new
				messageText: (
					(#DHPubKeyLength1sMismatch2s &lt;&lt; #security &gt;&gt; 'Client public key vector length &lt;1s&gt;does not match stated key exchange message length &lt;2s&gt;')
						expandMacrosWith: vectorLength printString
						with: length printString);
				parameter: (Array with: vectorLength with: length);
				raise ].
		yc := LargePositiveInteger basicNew: vectorLength.
		vectorLength to: 1 by: -1 do: [ :i |
			yc basicAt: i put: aByteStream next ] ]</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	yc isNil
		ifTrue: [self writeByteLength: 0 on: aByteStream in: aConnection]
		ifFalse: [ | vectorLength |	
			vectorLength := yc basicSize.
			self writeByteLength: vectorLength + 2 on: aByteStream in: aConnection.
			aByteStream nextPut: (vectorLength bitShift: -8); nextPut: (vectorLength bitAnd: 255).
			vectorLength to: 1 by: -1 do: [ :i |
				aByteStream nextPut: (yc basicAt: i) ] ]</body>
</methods>

<methods>
<class-id>Security.ClientDHKeyExchangeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="yc">yc

	^yc</body>

<body package="SSL" selector="yc:">yc: aLargePositiveInteger

	yc := aLargePositiveInteger</body>
</methods>

<methods>
<class-id>Security.ClientDHKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>

<body package="SSL" selector="yc:">yc: aLargePositiveInteger

	^self new yc: aLargePositiveInteger</body>
</methods>

<methods>
<class-id>Security.ServerDHKeyExchangeMessage</class-id> <category>initialization</category>

<body package="SSL" selector="p:g:ys:">p: aPrime g: aGenerator ys: aServerPublicKey

	p := aPrime.
	g := aGenerator.
	ys := aServerPublicKey</body>
</methods>

<methods>
<class-id>Security.ServerDHKeyExchangeMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="parametersLength">parametersLength

	^6 "lengths" + p basicSize + g basicSize + ys basicSize</body>

<body package="SSL" selector="readParametersFrom:">readParametersFrom: aByteStream

	| vectorLength |
	vectorLength := (aByteStream next bitShift: 8) + aByteStream next.
	p := LargePositiveInteger basicNew: vectorLength.
	vectorLength to: 1 by: -1 do: [ :i |
			p basicAt: i put: aByteStream next ].
	vectorLength := (aByteStream next bitShift: 8) + aByteStream next.
	g := LargePositiveInteger basicNew: vectorLength.
	vectorLength to: 1 by: -1 do: [ :i |
			g basicAt: i put: aByteStream next ].
	vectorLength := (aByteStream next bitShift: 8) + aByteStream next.
	ys := LargePositiveInteger basicNew: vectorLength.
	vectorLength to: 1 by: -1 do: [ :i |
			ys basicAt: i put: aByteStream next ].</body>

<body package="SSL" selector="writeParametersOn:">writeParametersOn: aByteStream

	(Array with: p with: g with: ys) do: [ :param || vectorLength |
		vectorLength := param basicSize.
		aByteStream nextPut: (vectorLength bitShift: -8); nextPut: (vectorLength bitAnd: 255).
		vectorLength to: 1 by: -1 do: [ :i |
			aByteStream nextPut: (param basicAt: i) ] ]</body>
</methods>

<methods>
<class-id>Security.ServerDHKeyExchangeMessage</class-id> <category>accessing</category>

<body package="SSL" selector="g">g
	^g</body>

<body package="SSL" selector="p">p
	^p</body>

<body package="SSL" selector="ys">ys
	^ys</body>
</methods>

<methods>
<class-id>Security.ServerDHKeyExchangeMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="p:g:ys:">p: aPrime g: aGenerator ys: aServerPublicKey

	^self new p: aPrime g: aGenerator ys: aServerPublicKey</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage</class-id> <category>accessing</category>

<body package="SSL" selector="authorityNames">authorityNames

	^authorityNames</body>

<body package="SSL" selector="certificateTypes">certificateTypes

	^certificateTypes</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage</class-id> <category>initialization</category>

<body package="SSL" selector="certificateTypes:authorityNames:">certificateTypes: aTypeCodeCollection authorityNames: anX509NameCollection

	certificateTypes := aTypeCodeCollection.
	authorityNames := anX509NameCollection</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length typesLength namesLength |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	typesLength := aByteStream next.
	certificateTypes := OrderedCollection new.
	typesLength timesRepeat: [
		certificateTypes add: (self class typeFor: aByteStream next) ].
	namesLength := (aByteStream next bitShift: 8) bitOr: aByteStream next.
	length - typesLength -namesLength = 3 ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidCRLength1s2s3s &lt;&lt; #security &gt;&gt; 'Total CertificateRequest length &lt;1s&gt; does not match the sum of certificate types length &lt;2s&gt; and authority names length &lt;3s&gt;')
					expandMacrosWith: length printString
					with: typesLength printString
					with: namesLength printString);
			parameter: (Array with: length with: typesLength with: namesLength);
			raise ].
	authorityNames := OrderedCollection new.
	[ namesLength &gt; 0 ] whileTrue: [ | nameLength |
		nameLength := (aByteStream next bitShift: 8) bitOr: aByteStream next.
		authorityNames add: ( _.X509.Name fromBytes: ( aByteStream next: nameLength )).
		namesLength := namesLength - nameLength - 2 ]</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| typesLength nameBytes namesLength |
	super writeOn: aByteStream in: aConnection.
	typesLength := certificateTypes size.
	nameBytes := authorityNames collect: [ :name | name getDNBytes ].
	namesLength := (nameBytes inject: 0 into: [ :t :n | t + n size + 2 ]).
	self writeByteLength: 3 "lengths" + typesLength + namesLength on: aByteStream in: aConnection.
	aByteStream nextPut: typesLength.
	certificateTypes do: [ :t | aByteStream nextPut: (self class codeFor: t) ].
	aByteStream nextPut: (namesLength bitShift: -8); nextPut: (namesLength bitAnd: 255).
	nameBytes do: [ :nb |
		aByteStream nextPut: (nb size bitShift: -8); nextPut: (nb size bitAnd: 255).
		aByteStream nextPutAll: nb ]</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage class</class-id> <category>certificate types</category>

<body package="SSL" selector="buildCertificateTypes">buildCertificateTypes
"This is a mapping between certificate type names and codes as defined by the SSL 3.0 Spec:
	rsa_sign (1)	RSA signing and key exchange
	dss_sign (2)	DSA signing only
	rsa_fixed_dh (3)	RSA signing with fixed Diffie-Hellman key exchange
	dss_fixed_dh (4)	DSA signing with fixed Diffie-Hellman key exchange
	rsa_ephemeral_dh (5)	RSA signing with ephemeral Diffie-Hellman key exchange
	dss_ephemeral_dh (6)	DSA signing with ephemeral Diffie-Hellman key exchange
	fortezza_dms (20) - I guess we can forget about this one."

	^#(rsa dsa rsaFixedDH dsaFixedDH rsaEphemeralDH dsaEphemeralDH)</body>

<body package="SSL" selector="certificateTypes">certificateTypes

	^CertificateTypes</body>

<body package="SSL" selector="codeFor:">codeFor: aSymbol

	^CertificateTypes indexOf: aSymbol</body>

<body package="SSL" selector="typeFor:">typeFor: anInteger

	^CertificateTypes at: anInteger</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^13</body>
</methods>

<methods>
<class-id>Security.CertificateRequestMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="certificateTypes:authorityNames:">certificateTypes: aTypeCodeCollection authorityNames: anX509NameCollection

	^self new certificateTypes: aTypeCodeCollection authorityNames: anX509NameCollection</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>private</category>

<body package="SSL" selector="commitStream:">commitStream: aFragmentStream

	ioStream isNil ifTrue: [
		EndOfStreamNotification raiseSignal: (
			#ConnectionClosed &lt;&lt; #security &gt;&gt; 'Connection Closed !') ].
	aFragmentStream
		trimLastRecord;
		fragmentsDo: [ :f |
			f writeOn: ioStream in: self.
			mutex critical: [
				recordCache size &lt; maxRecordsToCache ifTrue: [
					recordCache add: f ] ] ].
	ioStream flush.</body>

<body package="SSL" selector="keyMaterialStreamFrom:">keyMaterialStreamFrom: aSecret

	^(SecretMaterialStream forSecret: aSecret)
		setFragmentProvider: self message: #nextChunkOfMaterialFor:;
		yourself</body>

<body package="SSL" selector="masterSecretStreamFrom:">masterSecretStreamFrom: aSecret

	^(SecretMaterialStream forSecret: aSecret)
		setFragmentProvider: self message: #nextChunkOfSecretFor:;
		yourself</body>

<body package="SSL" selector="newRecordForProtocol:">newRecordForProtocol: anInteger

	^(	mutex critical: [
			recordCache isEmpty
				ifTrue: [ SSLRecord new
						setFragment: (ByteArray new: SSLRecord maxEncryptedFragmentSize)
						size: SSLRecord maxFragmentSize;
						yourself ]
				ifFalse: [ recordCache removeLast
						setSize: SSLRecord maxFragmentSize;
						yourself ] ]
	)	initializeProtocol: anInteger
		major: self majorVersion
		minor: self minorVersion;
		yourself</body>

<body package="SSL" selector="newRecordStreamForProtocol:">newRecordStreamForProtocol: aNumber

	^(FragmentStream onFragment: (self newRecordForProtocol: aNumber)
	)	setFragmentProvider: self message: #nextEmptyRecordFor:;
		yourself</body>

<body package="SSL" selector="nextChunkOfMaterialFor:">nextChunkOfMaterialFor: aSecretStream
"This represent one iteration of the SSL 3.0 alogrithm for generation of key material from master_secret (Section 8.2.2 of the Spec). The algorithm is defined as follows:
	key_block =
		MD5(master_secret + SHA('A' + master_secret + ServerHello.random + ClientHello.random)) +
		MD5(master_secret + SHA('BB' + master_secret + ServerHello.random + ClientHello.random)) +
		MD5(master_secret + SHA('CCC' + master_secret + ServerHello.random + ClientHello.random)) +
		[...]		
The master_secret is taken from aSecretStream, so aSecretStream has to be pre-initialized with master_secret. The method is written so that it is suitable as a fragment providing message for a fragment stream"

	| chunkNumber innerHash |
	chunkNumber := aSecretStream fragments size + 1.	
	innerHash := SHA byteHash: (
					(ByteArray new: chunkNumber withAll: 16r40 + chunkNumber),
					aSecretStream secret,
					serverRandom,
					clientRandom).
	^MD5 byteHash: (aSecretStream secret, innerHash)</body>

<body package="SSL" selector="nextChunkOfSecretFor:">nextChunkOfSecretFor: aSecretStream
"This represents one iteration of the SSL 3.0 algorithm for generation of master_secret from pre_master_secret (Section 8.1 of the spec). The algorithm is defined as follows:
	master_secret =
		MD5(pre_master_secret + SHA('A' + pre_master_secret + ClientHello.random + ServerHello.random)) +
		MD5(pre_master_secret + SHA('BB' + pre_master_secret + ClientHello.random + ServerHello.random)) +
		MD5(pre_master_secret + SHA('CCC' + pre_master_secret + ClientHello.random + ServerHello.random))	
The size of the master_secret is 48 bytes, so it needs exactly 3 iterations of the algorithm. The pre_master_secret is taken from aSecretStream, so aSecretStream has to be pre initialized with pre_master_secret. The method is written so that it is suitable as a fragment providing message for a fragment stream"

	| chunkNumber innerHash |
	chunkNumber := aSecretStream fragments size + 1.	
	innerHash := SHA byteHash: (
					(ByteArray new: chunkNumber withAll: 16r40 + chunkNumber),
					aSecretStream secret,
					clientRandom,
					serverRandom).
	^MD5 byteHash: (aSecretStream secret, innerHash)</body>

<body package="SSL" selector="resumptionFallbackSession:">resumptionFallbackSession: aSession

	session := aSession</body>

<body package="SSL" selector="serverReconnectHello:">serverReconnectHello: aHelloMessage

	session := session serverReconnect: self hello: aHelloMessage</body>

<body package="SSL" selector="signatureFor:cipherSpec:macSecret:sequenceNumber:">signatureFor: aRecord cipherSpec: aCipherSpec macSecret: macSecret sequenceNumber: anInteger
"This is the SSL 3.0 MAC generation algorithm which is defined (section 7.2.3.1 of the spec) as follows (hash is either MD5 or SHA):
	innerHash := hash(MAC_write_secret + pad_1 + seq_num + type + length + content)
	result := hash(MAC_write_secret + pad_2 + innerHash)
Note that a sizeable chunk of the hash input is constant for a given cipher spec, that's why the signingPads are cached."

	^mutex critical: [ | innerHash sigPad prefixSize |
		sigPad := aCipherSpec signingPad1: macSecret.
		prefixSize := macSecret size + aCipherSpec macPaddingSize.
		(WriteStream with: sigPad)
			reset;
			skip: prefixSize;
			nextPutAll: (anInteger asBigEndianByteArrayPaddedTo: 8);
			nextPut: aRecord protocol;
			nextPut: (aRecord size bitShift: -8);
			nextPut: (aRecord size bitAnd: 255).
		innerHash := aCipherSpec digestStream: (
			(	FragmentStream on: (Array with: sigPad with: aRecord)
			)	noGrowth;
				yourself ).
		sigPad := aCipherSpec signingPad2: macSecret.
		sigPad replaceFrom: prefixSize + 1 to: sigPad size with: innerHash.
		aCipherSpec digest: sigPad ]</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>services</category>

<body package="SSL" selector="accept">accept
"Handshake as a server. Accept without validating the server's certificate subject.
Note that this pretty much blows out authentication of the client party (if it is requested),
because an intruder can simply present his own perfectly valid certificate.
The communication will be encrypted allright, but you can't be sure whom you're really talking to !"

	self acceptSubject: nil</body>

<body package="SSL" selector="acceptSubject:">acceptSubject: aSubjectValidationBlock
"Handshake as a server. Use aSubjectValidationBlock to verify client's certificate subject (if client authentication is requested).
aSubjectValidationBlock one argument block invoked with a collection of name attribute-&gt;value associations and should return aBoolean."

	session := session accept: self subjectValidator: aSubjectValidationBlock</body>

<body package="SSL" selector="close">close
"Close the secure channel, i.e. send CloseAlert and shutdown the connection.
Note that if the associated data stream is closed, the connection is closed automatically."

	self isConnected ifTrue: [
		self 
			sendMessage: AlertMessage close_notify;
			shutdown ]</body>

<body package="SSL" selector="connect">connect
"Handshake as a client. Connect without validating the server's certificate subject.
Note that this pretty much blows out authentication of the server party,
because an intruder can simply present his own perfectly valid certificate.
The communication will be encrypted allright, but you can't be sure whom you're really talking to !"

	self connectSubject: nil</body>

<body package="SSL" selector="connectSubject:">connectSubject: aSubjectValidationBlock
"Handshake as a client. Use aSubjectValidationBlock to verify server's certificate subject.
aSubjectValidationBlock one argument block invoked with a collection of name attribute-&gt;value associations and should return aBoolean."

	session connect: self subjectValidator: aSubjectValidationBlock</body>

<body package="SSL" selector="isConnected">isConnected

	^ioStream notNil</body>

<body package="SSL" selector="renegotiate">renegotiate
"SSL servers can request renegotiation of the security parameters. This is supposed to be used in case of long lasting connections when the amount of time or the amount of information passed through the connection starts to increase the chances of a successful attack to unacceptable level."

	session isServer
		ifTrue: [ self sendMessage: HelloRequestMessage new.
			self acceptSubject: session subjectValidator ]
		ifFalse: [ self connectSubject: session subjectValidator ]</body>

<body package="SSL" selector="sendMessage:">sendMessage: aMessage
"Send an SSL message outside of the writeStream. Useful for sending Alerts and such"

	| s |
	s := self newRecordStreamForProtocol: aMessage protocol.
	self triggerEvent: #sendingMessage: with: aMessage.
	aMessage writeOn: s in: self.
	self commitStream: s</body>

<body package="SSL" selector="shutdown">shutdown
"Shutdown the IO skipping close alert, note that using this opens a hole for truncation attack.
Use #close instead if possible."

	ioStream notNil ifTrue: [
		[ ioStream close
		] ensure: [ ioStream := nil ] ]</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>data stream</category>

<body package="SSL" selector="appendStream">appendStream

	^(self withEncoding: #default) appendStream</body>

<body package="SSL" selector="close:">close: aFragmentStream

	self isConnected ifTrue: [
		self flush: aFragmentStream.
		self close ]</body>

<body package="SSL" selector="dataProtocol">dataProtocol

	^23</body>

<body package="SSL" selector="dataReadStream">dataReadStream

	^readStream</body>

<body package="SSL" selector="dataWriteStream">dataWriteStream

	^writeStream</body>

<body package="SSL" selector="flush:">flush: aFragmentStream

	writeStream = aFragmentStream ifTrue: [
		self commitStream: aFragmentStream.
		aFragmentStream dump ]</body>

<body package="SSL" selector="nextDataRecordFor:">nextDataRecordFor: aFragmentStream

	| rec stream |
	rec :=
		[	[	self nextRecordFor: aFragmentStream.
			] on: SSLError do: [ :ex |
				session beNonResumable.
				self sendMessage: ex alertMessage.
				ex pass ]
		] 	on: EndOfStreamNotification do: [ :ex |
			SSLRecordError raiseSignal: (
				#UnexpectedEndOfStream &lt;&lt; #security &gt;&gt; 'Unexpected end of stream !') ].
	(rec isNil or: [ rec protocol = self dataProtocol ]) ifTrue: [^rec].
	stream := (FragmentStream onFragment: rec)
				setFragmentProvider: self message: #nextRecordFor:;
				yourself.
	[ self isConnected and: [ stream basicAtEnd not ] ] whileTrue: [
		self processMessage: (
			[	[	rec messageClass readFrom: stream in: self
				] on: SSLError do: [ :ex |
					session beNonResumable.
					self sendMessage: ex alertMessage.
					ex pass ]
			] 	on: EndOfStreamNotification do: [ :ex |
				SSLMessageError raiseSignal: (
					#UnexpectedEndOfStream &lt;&lt; #security &gt;&gt; 'Unexpected end of stream !') ] ) ].
	^self nextDataRecordFor: aFragmentStream</body>

<body package="SSL" selector="nextEmptyDataRecordFor:">nextEmptyDataRecordFor: aFragmentStream
"This is a fragment provider for write record steam"

	^self newRecordForProtocol: self dataProtocol</body>

<body package="SSL" selector="processMessage:">processMessage: aMsg
"Handle a non application message that came in after the handshake"

	aMsg isAlert ifTrue: [
		aMsg = AlertMessage close_notify
			ifTrue: [ self close ]
			ifFalse: [ session beNonResumable.
				aMsg raiseException ].
		^self].
	((aMsg isKindOf: HelloRequestMessage) and: [ session isServer not ])
		ifTrue: [session clientReconnect: self. ^self ].
	((aMsg isKindOf: HelloMessage) and: [ session isServer ])
		ifTrue: [self serverReconnectHello: aMsg. ^self ].
	session beNonResumable.
	SSLUnexpectedMessage new
		messageText: (
			(#UnexpectedMessage1s &lt;&lt; #security &gt;&gt; 'Unexpected message &lt;1s&gt;')
				expandMacrosWith: aMsg printString);
		parameter: aMsg;
		sendIn: self</body>

<body package="SSL" selector="readAppendStream">readAppendStream

	^(self withEncoding: #default) readAppendStream</body>

<body package="SSL" selector="readStream">readStream

	^(self withEncoding: #default) readStream</body>

<body package="SSL" selector="withEncoding:">withEncoding: aStreamEncoderName

	^SSLEncodedStreamConstructor
		on: self
		encoding: aStreamEncoderName</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>handshaking</category>

<body package="SSL" selector="changeReadCipherSpec:">changeReadCipherSpec: keyMaterial

	readSequenceNumber := 0.
	readMACSecret := keyMaterial at: 1.
	readKey := keyMaterial at: 2.
	readIV := keyMaterial at: 3.
	pendingReadCipherSpec initializeBulkCipherWithKey: readKey andIV: readIV.
	activeReadCipherSpec := pendingReadCipherSpec.
	pendingReadCipherSpec := SSLCipherSpec null.</body>

<body package="SSL" selector="changeWriteCipherSpec:">changeWriteCipherSpec: keyMaterial

	writeSequenceNumber := 0.
	writeMACSecret := keyMaterial at: 1.
	writeKey := keyMaterial at: 2.
	writeIV := keyMaterial at: 3.
	pendingWriteCipherSpec initializeBulkCipherWithKey: writeKey andIV: writeIV.
	activeWriteCipherSpec := pendingWriteCipherSpec.
	pendingWriteCipherSpec := SSLCipherSpec null.</body>

<body package="SSL" selector="cipherSuite">cipherSuite

	^session cipherSuite</body>

<body package="SSL" selector="generateKeyMaterialUsing:">generateKeyMaterialUsing: aMasterSecret
"This implements the process as prescribed in section 8.2.2 of SSL3.0 Spec. The parameters are initialized from the key material in specific order. This implementation assumes that this connection's session does have the master secret and that both client and server random sequences are known."

	| keyMaterialGenerator clientSpec serverSpec serverKeyMaterial clientKeyMaterial |
	keyMaterialGenerator := self keyMaterialStreamFrom: aMasterSecret.
	serverKeyMaterial := Array new: 3.
	clientKeyMaterial := Array new: 3.
	session isServer "Which cipher spec to use for what parameters depends on my role"
		ifTrue: [clientSpec := pendingReadCipherSpec. serverSpec := pendingWriteCipherSpec]
		ifFalse: [clientSpec := pendingWriteCipherSpec. serverSpec := pendingReadCipherSpec].
	clientKeyMaterial at: 1 put: (keyMaterialGenerator next: clientSpec hashSize).
	serverKeyMaterial at: 1 put: (keyMaterialGenerator next: serverSpec hashSize).
	clientKeyMaterial at: 2 put: (keyMaterialGenerator next: clientSpec keySize).
	serverKeyMaterial at: 2 put: (keyMaterialGenerator next: serverSpec keySize).
	clientKeyMaterial at: 3 put: (keyMaterialGenerator next: clientSpec ivSize).
	serverKeyMaterial at: 3 put: (keyMaterialGenerator next: serverSpec ivSize).
	^Array with: clientKeyMaterial with: serverKeyMaterial</body>

<body package="SSL" selector="pendingReadCipherSpec:">pendingReadCipherSpec: aCipherSpec

	pendingReadCipherSpec := aCipherSpec</body>

<body package="SSL" selector="pendingWriteCipherSpec:">pendingWriteCipherSpec: aCipherSpec

	pendingWriteCipherSpec := aCipherSpec</body>

<body package="SSL" selector="setClientRandom:">setClientRandom: a32ByteArray

	clientRandom := a32ByteArray</body>

<body package="SSL" selector="setServerRandom:">setServerRandom: a32ByteArray

	serverRandom := a32ByteArray</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>record layer</category>

<body package="SSL" selector="decrypt:">decrypt: aRecord

	^activeReadCipherSpec isEncrypting
		ifTrue: [ activeReadCipherSpec bulkCipher decryptInPlace: aRecord fragment from: 1 to: aRecord size ]
		ifFalse: [ aRecord size ]</body>

<body package="SSL" selector="encrypt:">encrypt: aRecord

	^activeWriteCipherSpec isEncrypting
		ifTrue: [ activeWriteCipherSpec bulkCipher encryptInPlace: aRecord fragment from: 1 to: aRecord size ]
		ifFalse: [ aRecord size ]</body>

<body package="SSL" selector="nextEmptyRecordFor:">nextEmptyRecordFor: aFragmentStream
"This is a fragment provider for write record steam"

	^self newRecordForProtocol: aFragmentStream fragments last protocol</body>

<body package="SSL" selector="nextRecordFor:">nextRecordFor: aFragmentStream
"This is used for access from a fragment stream"

	| dumped |
	ioStream isNil ifTrue: [ ^nil ].
	dumped := aFragmentStream readNextFragmentDump.
	^(mutex critical: [ | new |
		new := dumped isEmpty
			ifTrue: [ recordCache isEmpty
					ifTrue: [ SSLRecord new ]
					ifFalse: [ recordCache removeLast ] ]
			ifFalse: [ dumped removeLast ].
		[ dumped isEmpty or: [ recordCache size &gt;= MaxRecordsToCache ] ] whileFalse: [
			recordCache addLast: dumped removeLast ].
		new ]
	)	readFrom: ioStream in: self;
		yourself</body>

<body package="SSL" selector="readHashSize">readHashSize

	^activeReadCipherSpec hashSize</body>

<body package="SSL" selector="readSignatureFor:">readSignatureFor: aRecord

	| sig |
	sig := self
		signatureFor: aRecord
		cipherSpec: activeReadCipherSpec
		macSecret: readMACSecret
		sequenceNumber: readSequenceNumber.
	readSequenceNumber := readSequenceNumber + 1 bitAnd: 16rFFFFFFFF.
	^sig</body>

<body package="SSL" selector="writeHashSize">writeHashSize

	^activeWriteCipherSpec hashSize</body>

<body package="SSL" selector="writeSignatureFor:">writeSignatureFor: aRecord

	| sig |
	sig := self
		signatureFor: aRecord
		cipherSpec: activeWriteCipherSpec
		macSecret: writeMACSecret
		sequenceNumber: writeSequenceNumber.
	writeSequenceNumber := writeSequenceNumber + 1 bitAnd: 16rFFFFFFFF.
	^sig</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>accessing</category>

<body package="SSL" selector="context">context

	^session context</body>

<body package="SSL" selector="majorVersion">majorVersion

	^session majorVersion</body>

<body package="SSL" selector="maxRecordsToCache">maxRecordsToCache
	^maxRecordsToCache</body>

<body package="SSL" selector="maxRecordsToCache:">maxRecordsToCache: anObject
	maxRecordsToCache := anObject</body>

<body package="SSL" selector="minorVersion">minorVersion

	^session minorVersion</body>

<body package="SSL" selector="random">random

	^session random</body>

<body package="SSL" selector="session">session

	^session</body>
</methods>

<methods>
<class-id>Security.SSLConnection</class-id> <category>initialization</category>

<body package="SSL" selector="initializeFor:in:">initializeFor: aReadAppendByteStream in: aSession

	ioStream := aReadAppendByteStream.
	session := aSession.
	pendingReadCipherSpec := SSLCipherSpec null.
	pendingWriteCipherSpec := SSLCipherSpec null.
	activeReadCipherSpec := SSLCipherSpec null.
	activeWriteCipherSpec := SSLCipherSpec null.
	writeStream := (FragmentStream onFragment: nil)
					setFragmentProvider: self message: #nextEmptyDataRecordFor:;
					yourself.
	readStream := (FragmentStream onFragment: nil)
					setFragmentProvider: self message: #nextDataRecordFor:;
					yourself.
	recordCache := OrderedCollection new: MaxRecordsToCache.
	mutex := RecursionLock new.
	maxRecordsToCache := MaxRecordsToCache.</body>
</methods>

<methods>
<class-id>Security.SSLConnection class</class-id> <category>events</category>

<body package="SSL" selector="eventsTriggered">eventsTriggered

	^#( "These 2 events provide the fragment containing the encrypted bytes and the size of the bytes in it"
		sendingEncryptedBytes:size:
		receivingEncryptedBytes:size:
		"These 2 events provide the fragment containing the decrtyped bytes with signature.
		The signature bytes are not included in the size, one is expected to derive the signature size from Connection&gt;&gt;read/writeHashSize"
		sendingSignedBytes:size:
		receivingSignedBytes:size:
		"These events are triggered for all non-data SSL messages, i.e. Hanshake, Alert and ChangeCipherSpec protocols"
		sendingMessage:
		receivingMessage:)</body>
</methods>

<methods>
<class-id>Security.SSLConnection class</class-id> <category>instance creation</category>

<body package="SSL" selector="newFor:in:">newFor: aReadAppendByteStream in: aSession

	^self new initializeFor: aReadAppendByteStream in: aSession</body>
</methods>

<methods>
<class-id>Security.SSLConnection class</class-id> <category>constants</category>

<body package="SSL" selector="defaultMaxRecordsToCache">defaultMaxRecordsToCache

	^20</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>status</category>

<body package="SSL" selector="binary">binary</body>

<body package="SSL" selector="close">close

	^newFragmentProvider close: self</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>accessing</category>

<body package="SSL" selector="addFragment:">addFragment: aFragment

	^fragments add: aFragment</body>

<body package="SSL" selector="commit">commit

	^self flush</body>

<body package="SSL" selector="contents">contents

	| pos result |
	fragments isEmpty ifTrue: [^OrderedCollection new].
	pos := 0.
	1 to: fragmentIndex - 1 do: [ :i |
		pos := pos + (fragments at: i) size ].
	pos := self basicAtEnd ifTrue: [pos] ifFalse: [pos + fragmentPosition].
	result := fragments first contentsSpecies new: pos - 1.
	pos := 0.
	1 to: fragmentIndex - 1 do: [ :i || end frg |
		frg := fragments at: i.
		end := pos + frg size.
		result replaceFrom: pos + 1 to: end with: frg.
		pos := end ].
	self basicAtEnd ifFalse: [
		result replaceFrom: pos + 1 to: fragmentPosition - 1 with: fragments last ].
	^result</body>

<body package="SSL" selector="flush">flush

	^newFragmentProvider flush: self</body>

<body package="SSL" selector="fragment">fragment

	self checkAndHandleAtEnd.
	^fragments at: fragmentIndex</body>

<body package="SSL" selector="fragmentIndex">fragmentIndex

	^fragmentIndex</body>

<body package="SSL" selector="fragmentPosition">fragmentPosition

	^fragmentPosition</body>

<body package="SSL" selector="fragments">fragments

	^fragments</body>

<body package="SSL" selector="next">next

	^[	| e |
		e := self fragment at: fragmentPosition.
		self advanceFragmentPosition: 1.
		e
	]	on: EndOfStreamNotification
		do: [ :ex | ex outer ]</body>

<body package="SSL" selector="nextPut:">nextPut: anObject

	self fragment at: fragmentPosition put: anObject.
	self advanceFragmentPosition: 1.
	^anObject</body>

<body package="SSL" selector="position">position

	| total |
	total := -1. "make 'position' zero based as with standard streams"
	1 to: fragmentIndex - 1 do: [ :i |
		total := total + (fragments at: i) size ].
	"Note that it fits the 'atEnd' position as well, i.e. on more than the present size"
	^total + self fragmentPosition</body>

<body package="SSL" selector="position:">position: newIndex

	| total oldFragmentIndex |
	newIndex &lt; 0 ifTrue: [^PositionOutOfBoundsError raiseWith: newIndex].
	total := newIndex + 1. "The 'position' is zero based to conform with standard streams"
	oldFragmentIndex := fragmentIndex.
	fragmentIndex := 1.
	[	[ 	self fragment size &lt; total
		] whileTrue: [
			total := total - self fragment size.
			fragmentIndex := fragmentIndex + 1 ].
		fragmentPosition := total
	] on: EndOfStreamNotification do: [ :ex |
		fragmentIndex := oldFragmentIndex.
		PositionOutOfBoundsError raiseWith: newIndex ]</body>

<body package="SSL" selector="skip:">skip: offset

	self position: self position + offset</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>services</category>

<body package="SSL" selector="dump">dump

	fragments := fragments species new.
	fragmentIndex := fragmentPosition := 1</body>

<body package="SSL" selector="fragmentsDo:">fragmentsDo: aBlock

	fragments do: [ :f | aBlock value: f ]</body>

<body package="SSL" selector="setToEnd">setToEnd

	fragmentIndex := fragments size + 1.
	fragmentPosition := 1.</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>private</category>

<body package="SSL" selector="advanceFragmentPosition:">advanceFragmentPosition: step

	fragmentPosition := fragmentPosition + step.
	[ fragmentIndex &lt;= fragments size and: [ fragmentPosition &gt; self fragment size ] ]
		whileTrue: [
			fragmentPosition := fragmentPosition - self fragment size.
			fragmentIndex := fragmentIndex + 1 ]</body>

<body package="SSL" selector="checkAndHandleAtEnd">checkAndHandleAtEnd

	"The loop is to handle empty fragments"
	[ self basicAtEnd ] whileTrue: [ | nf |
		nf := newFragmentProvider perform: newFragmentMessage with: self.
		nf isNil ifTrue: [ ^self class endOfStreamSignal raiseRequestFrom: self ].
		self
			addFragment: nf;
			advanceFragmentPosition: 0 ]</body>

<body package="SSL" selector="close:">close: aFragmentStream
"This gets sent to a fragment provider when the stream is told to close.
Since sometimes the stream itself is the provider, we need to implement it"

	^self</body>

<body package="SSL" selector="contentsSpecies">contentsSpecies

	^self fragment species</body>

<body package="SSL" selector="flush:">flush: aFragmentStream
"This gets sent to a fragment provider when the stream is told to flush.
Since sometimes the stream itself is the provider, we need to implement it"

	^self</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>ssl services</category>

<body package="SSL" selector="readNextFragmentDump">readNextFragmentDump
"This is called from SSLConnection when the read data stream is atEnd.
Make sure this condition remains valid"

	| last dumped |
	fragments size &lt; 2 ifTrue: [ ^fragments species new ].
	last := fragments removeLast.
	dumped := fragments.
	fragments := fragments species with: last.
	fragmentIndex := 2.
	^dumped</body>

<body package="SSL" selector="trimLastRecord">trimLastRecord

	self basicAtEnd ifFalse: [
		fragments last setSize: fragmentPosition - 1.
		fragmentIndex := fragmentIndex + 1.
		fragmentPosition := 1 ]</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>testing</category>

<body package="SSL" selector="atEnd">atEnd

	^self basicAtEnd and: [ self endTest ]</body>

<body package="SSL" selector="basicAtEnd">basicAtEnd

	^fragmentIndex &gt; fragments size</body>

<body package="SSL" selector="endTest">endTest

	^[	self checkAndHandleAtEnd.
		false
	]	on: EndOfStreamNotification
		do: [ :ex | ex return: true ]</body>

<body package="SSL" selector="isFragmentStream">isFragmentStream
	^true</body>

<body package="SSL" selector="isReadable">isReadable

	^true</body>

<body package="SSL" selector="isWritable">isWritable

	^true</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>growth policies</category>

<body package="SSL" selector="constantFragmentFor:">constantFragmentFor: aFragmentStream
"Constant Fragments policy message"

	^fragments first species new: fragments first size</body>

<body package="SSL" selector="constantFragments">constantFragments
"Set Constant Fragments policy"

	newFragmentMessage := #constantFragmentFor:</body>

<body package="SSL" selector="noFragmentFor:">noFragmentFor: aFragmentStream
"No Growth policy message"

	^nil</body>

<body package="SSL" selector="noGrowth">noGrowth
"Set No Growth policy"

	newFragmentMessage := #noFragmentFor:</body>

<body package="SSL" selector="setFragmentProvider:message:">setFragmentProvider: anObject message: aSelector

	newFragmentProvider := anObject.
	newFragmentMessage := aSelector</body>
</methods>

<methods>
<class-id>Security.FragmentStream</class-id> <category>initialization</category>

<body package="SSL" selector="initializeOn:">initializeOn: aFragmentCollection

	fragments := aFragmentCollection.
	fragmentIndex := fragmentPosition := 1.
	self advanceFragmentPosition: 0. "To handle empty fragments"
	newFragmentProvider := self.
	self constantFragments</body>
</methods>

<methods>
<class-id>Security.FragmentStream class</class-id> <category>instance creation</category>

<body package="SSL" selector="on:">on: aFragmentCollection

	^self basicNew initializeOn: aFragmentCollection</body>

<body package="SSL" selector="onFragment:">onFragment: aFragment

	^self on: (aFragment isNil
		ifTrue: [OrderedCollection new]
		ifFalse: [OrderedCollection with: aFragment])</body>
</methods>

<methods>
<class-id>Security.ServerHelloMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| lengthOffset compression |
	lengthOffset := super readFrom: aByteStream in: aConnection.
	cipherSuite := SSLCipherSuite readFrom: aByteStream in: aConnection.
	"Compression methods are not supported, so it's set as 0 indicating no compression"
	compression := aByteStream next.
	"Now let's check if the total length matches what we read so far"
	lengthOffset = 3 "cipher(2)+compresion(1)" ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidSHLength1s &lt;&lt; #security &gt;&gt; 'Received server hello with mismatched message length &lt;1s&gt;')
					expandMacrosWith: lengthOffset printString);
			parameter: lengthOffset;
			raise ].
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	"Remember all lengths are in bytes"
	self writeOn: aByteStream in: aConnection lengthOffset: 3 "cipher(2)+compresion(1)".
	cipherSuite writeOn: aByteStream in: aConnection.
	"Compression methods are not supported, so the ususal thing is to write 0 indicating no compression"
	aByteStream nextPut: 0</body>
</methods>

<methods>
<class-id>Security.ServerHelloMessage</class-id> <category>initialization</category>

<body package="SSL" selector="major:minor:random:session:suite:">major: majVer minor: minVer random: ba session: id suite: ciphSuite

	super major: majVer minor: minVer random: ba session: id.
	cipherSuite := ciphSuite</body>
</methods>

<methods>
<class-id>Security.ServerHelloMessage</class-id> <category>accessing</category>

<body package="SSL" selector="cipherSuite">cipherSuite

	^cipherSuite</body>
</methods>

<methods>
<class-id>Security.ServerHelloMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="major:minor:random:session:suite:">major: majVer minor: minVer random: ba session: id suite: ciphSuite

	^self new major: majVer minor: minVer random: ba session: id suite: ciphSuite</body>
</methods>

<methods>
<class-id>Security.ServerHelloMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^2</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>initialization</category>

<body package="SSL" selector="SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA">SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA

	keyExchange := SSLDHKeyExchange ephemeralDSS.
	cipherSpec := SSLCipherSpec ThreeDES_EDE_CBC_SHA.
	code := 16r13</body>

<body package="SSL" selector="SSL_DHE_DSS_WITH_DES_CBC_SHA">SSL_DHE_DSS_WITH_DES_CBC_SHA

	keyExchange := SSLDHKeyExchange ephemeralDSS.
	cipherSpec := SSLCipherSpec DES_CBC_SHA.
	code := 16r12</body>

<body package="SSL" selector="SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA">SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA

	keyExchange := SSLDHKeyExchange ephemeralRSA.
	cipherSpec := SSLCipherSpec ThreeDES_EDE_CBC_SHA.
	code := 16r16</body>

<body package="SSL" selector="SSL_DHE_RSA_WITH_DES_CBC_SHA">SSL_DHE_RSA_WITH_DES_CBC_SHA

	keyExchange := SSLDHKeyExchange ephemeralRSA.
	cipherSpec := SSLCipherSpec DES_CBC_SHA.
	code := 16r15</body>

<body package="SSL" selector="SSL_DH_anon_WITH_3DES_EDE_CBC_SHA">SSL_DH_anon_WITH_3DES_EDE_CBC_SHA

	keyExchange := SSLDHKeyExchange anonymous.
	cipherSpec := SSLCipherSpec ThreeDES_EDE_CBC_SHA.
	code := 16r1B</body>

<body package="SSL" selector="SSL_DH_anon_WITH_DES_CBC_SHA">SSL_DH_anon_WITH_DES_CBC_SHA

	keyExchange := SSLDHKeyExchange anonymous.
	cipherSpec := SSLCipherSpec DES_CBC_SHA.
	code := 16r1A</body>

<body package="SSL" selector="SSL_DH_anon_WITH_RC4_128_MD5">SSL_DH_anon_WITH_RC4_128_MD5

	keyExchange := SSLDHKeyExchange anonymous.
	cipherSpec := SSLCipherSpec RC4_128_MD5.
	code := 16r18</body>

<body package="SSL" selector="SSL_NULL_WITH_NULL_NULL">SSL_NULL_WITH_NULL_NULL

	keyExchange := nil.
	cipherSpec := SSLCipherSpec NULL_NULL.
	code := 0</body>

<body package="SSL" selector="SSL_RSA_WITH_3DES_EDE_CBC_SHA">SSL_RSA_WITH_3DES_EDE_CBC_SHA

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec ThreeDES_EDE_CBC_SHA.
	code := 10</body>

<body package="SSL" selector="SSL_RSA_WITH_DES_CBC_SHA">SSL_RSA_WITH_DES_CBC_SHA

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec DES_CBC_SHA.
	code := 9</body>

<body package="SSL" selector="SSL_RSA_WITH_NULL_MD5">SSL_RSA_WITH_NULL_MD5

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec NULL_MD5.
	code := 1</body>

<body package="SSL" selector="SSL_RSA_WITH_NULL_SHA">SSL_RSA_WITH_NULL_SHA

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec NULL_SHA.
	code := 2</body>

<body package="SSL" selector="SSL_RSA_WITH_RC4_128_MD5">SSL_RSA_WITH_RC4_128_MD5

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec RC4_128_MD5.
	code := 4</body>

<body package="SSL" selector="SSL_RSA_WITH_RC4_128_SHA">SSL_RSA_WITH_RC4_128_SHA

	keyExchange := SSLRSAKeyExchange new.
	cipherSpec := SSLCipherSpec RC4_128_SHA.
	code := 5</body>

<body package="SSL" selector="unsupportedWithCode:">unsupportedWithCode: aByte

	code := aByte</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>reading/writing</category>

<body package="SSL" selector="write20On:in:">write20On: aByteStream in: aConnection

	aByteStream
		nextPut: (code bitShift: -16);
		nextPut: ((code bitShift: -8) bitAnd: 255);
		nextPut: (code bitAnd: 255)</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	aByteStream
		nextPut: 0;
		nextPut: code</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	cipherSpec isNil
		ifTrue: [aStream
				nextPutAll: (#UnsupportedSuite &lt;&lt; #security &gt;&gt; 'UnsupportedSuite') asString;
				nextPut: $(;
				print: code;
				nextPut: $) ]
		ifFalse: [aStream nextPutAll: 'SSL_'.
			keyExchange isNil
				ifTrue: [aStream nextPutAll: 'NULL']
				ifFalse: [keyExchange printOn: aStream].
			aStream
				nextPutAll: '_WITH_';
				print: cipherSpec ]</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>comparing</category>

<body package="SSL" selector="=">= aCipherSuite

	^self class = aCipherSuite class and: [
		code = aCipherSuite code ]</body>

<body package="SSL" selector="hash">hash

	^code</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>accessing</category>

<body package="SSL" selector="cipherSpec">cipherSpec

	^cipherSpec</body>

<body package="SSL" selector="code">code

	^code</body>

<body package="SSL" selector="hashSize">hashSize

	^cipherSpec hashSize</body>

<body package="SSL" selector="keyExchange">keyExchange

	^keyExchange</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite</class-id> <category>handshaking</category>

<body package="SSL" selector="cipherSpecClone">cipherSpecClone

	^(self class perform: self printString asSymbol) cipherSpec</body>

<body package="SSL" selector="receiveClientKeyExchange:">receiveClientKeyExchange: aHandshake

	^keyExchange receiveClientKeyExchange: aHandshake</body>

<body package="SSL" selector="receiveServerKeyExchange:">receiveServerKeyExchange: aHandshake

	^keyExchange receiveServerKeyExchange: aHandshake</body>

<body package="SSL" selector="sendClientKeyExchange:">sendClientKeyExchange: aHandshake

	^keyExchange sendClientKeyExchange: aHandshake</body>

<body package="SSL" selector="sendServerKeyExchange:">sendServerKeyExchange: aHandshake

	^keyExchange sendServerKeyExchange: aHandshake</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite class</class-id> <category>instance creation</category>

<body package="SSL" selector="newCode:">newCode: aNumber

	| sel |
	sel := Codes at: aNumber ifAbsent: [nil].
	^sel isNil
		ifTrue: [self new unsupportedWithCode: aNumber ]
		ifFalse: [self perform: sel]</body>

<body package="SSL" selector="null">null

	^self SSL_NULL_WITH_NULL_NULL</body>

<body package="SSL" selector="read20From:in:">read20From: aByteStream in: aConnection

	| code |
	(code := aByteStream next) isZero
		ifTrue: [^self readFrom: aByteStream in: aConnection ].
	code := (((code bitShift: 8) + aByteStream next) bitShift: 8) + aByteStream next.
	"Here's the list of 2.0 ciphersuites in from the 3.0 spec (Appendix E)
		SSL_RC4_128_WITH_MD5 = { 0x01,0x00,0x80 }
		SSL_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 }
		SSL_RC2_CBC_128_CBC_WITH_MD5 = { 0x03,0x00,0x80 }
		SSL_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 = { 0x04,0x00,0x80 }
		SSL_IDEA_128_CBC_WITH_MD5 = { 0x05,0x00,0x80 }
		SSL_DES_64_CBC_WITH_MD5 = { 0x06,0x00,0x40 }
		SSL_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 }
	Out of that list we only support RC4/MD5"
	^self newCode: code</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self newCode: ((aByteStream next bitShift: 8) + aByteStream next)</body>

<body package="SSL" selector="SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA">SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA

	^self new SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</body>

<body package="SSL" selector="SSL_DHE_DSS_WITH_DES_CBC_SHA">SSL_DHE_DSS_WITH_DES_CBC_SHA

	^self new SSL_DHE_DSS_WITH_DES_CBC_SHA</body>

<body package="SSL" selector="SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA">SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA

	^self new SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</body>

<body package="SSL" selector="SSL_DHE_RSA_WITH_DES_CBC_SHA">SSL_DHE_RSA_WITH_DES_CBC_SHA

	^self new SSL_DHE_RSA_WITH_DES_CBC_SHA</body>

<body package="SSL" selector="SSL_DH_anon_WITH_3DES_EDE_CBC_SHA">SSL_DH_anon_WITH_3DES_EDE_CBC_SHA

	^self new SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</body>

<body package="SSL" selector="SSL_DH_anon_WITH_DES_CBC_SHA">SSL_DH_anon_WITH_DES_CBC_SHA

	^self new SSL_DH_anon_WITH_DES_CBC_SHA</body>

<body package="SSL" selector="SSL_DH_anon_WITH_RC4_128_MD5">SSL_DH_anon_WITH_RC4_128_MD5

	^self new SSL_DH_anon_WITH_RC4_128_MD5</body>

<body package="SSL" selector="SSL_NULL_WITH_NULL_NULL">SSL_NULL_WITH_NULL_NULL

	^self new SSL_NULL_WITH_NULL_NULL</body>

<body package="SSL" selector="SSL_RSA_WITH_3DES_EDE_CBC_SHA">SSL_RSA_WITH_3DES_EDE_CBC_SHA

	^self new SSL_RSA_WITH_3DES_EDE_CBC_SHA</body>

<body package="SSL" selector="SSL_RSA_WITH_DES_CBC_SHA">SSL_RSA_WITH_DES_CBC_SHA

	^self new SSL_RSA_WITH_DES_CBC_SHA</body>

<body package="SSL" selector="SSL_RSA_WITH_NULL_MD5">SSL_RSA_WITH_NULL_MD5

	^self new SSL_RSA_WITH_NULL_MD5</body>

<body package="SSL" selector="SSL_RSA_WITH_NULL_SHA">SSL_RSA_WITH_NULL_SHA

	^self new SSL_RSA_WITH_NULL_SHA</body>

<body package="SSL" selector="SSL_RSA_WITH_RC4_128_MD5">SSL_RSA_WITH_RC4_128_MD5

	^self new SSL_RSA_WITH_RC4_128_MD5</body>

<body package="SSL" selector="SSL_RSA_WITH_RC4_128_SHA">SSL_RSA_WITH_RC4_128_SHA

	^self new SSL_RSA_WITH_RC4_128_SHA</body>
</methods>

<methods>
<class-id>Security.SSLCipherSuite class</class-id> <category>initialization</category>

<body package="SSL" selector="buildCodes">buildCodes
"Codes := self buildCodes"

	| c |
	c := Dictionary new.
	(self class selectors select: [ :s | 'SSL_*' match: s ])
		do: [ :s || cs |
			cs := self perform: s.
			c at: cs code put: s ].
	^c</body>
</methods>

<methods>
<class-id>Security.SSLKeyExchange</class-id> <category>handshaking</category>

<body package="SSL" selector="clientKeyExchangeMessageClass">clientKeyExchangeMessageClass

	self subclassResponsibility</body>

<body package="SSL" selector="receiveCertificateVerify:">receiveCertificateVerify: aHandshake

	| msg digest |
	"Compute the digest before getting the CertificateVerify record,
	otherwise the message digest will be off"
	digest := aHandshake certificateVerifyHandshakeDigest.
	msg := aHandshake next.
	(msg isKindOf: CertificateVerifyMessage) 
		ifTrue: [(aHandshake verifyClientSignature: msg signature of: digest ) 
				ifTrue: [aHandshake certificateVerify: msg]
				ifFalse: [SSLHandshakeFailure new
						messageText: (#ClientCertVerificationFailed &lt;&lt; #security &gt;&gt; 'Client certificate verification failed !');
						parameter: msg;
						sendIn: aHandshake]]
		ifFalse: [aHandshake unexpectedMessage: msg]</body>

<body package="SSL" selector="receiveClientKeyExchange:">receiveClientKeyExchange: aHandshake

	| msg |
	aHandshake shouldAuthenticateClient ifTrue: [
		msg := aHandshake next.
		(msg isKindOf: CertificateMessage) 
			ifTrue: [aHandshake
					validateCertificateChain: msg certificateChain;
					clientCertificate: msg]
			ifFalse: [msg = AlertMessage no_certificate 
					ifTrue: [SSLNoCertificate new
							messageText: (#ClientCertMissing &lt;&lt; #security &gt;&gt; 'Client did not provide its certificate !');
							sendIn: aHandshake as: AlertMessage handshake_failure]
					ifFalse: [aHandshake unexpectedMessage: msg]]].
	msg := aHandshake next.
	(msg class = self clientKeyExchangeMessageClass) ifFalse: [
		aHandshake unexpectedMessage: msg ].
	aHandshake clientKeyExchange: msg</body>

<body package="SSL" selector="receiveServerKeyExchange:">receiveServerKeyExchange: aHandshake

	self subclassResponsibility</body>

<body package="SSL" selector="sendCertificateVerify:usingKey:">sendCertificateVerify: aHandshake usingKey: aPrivateKey

	| msg |
	msg := CertificateVerifyMessage signature: (
			aHandshake signedMessageDigestUsingKey: aPrivateKey).
	aHandshake
		certificateVerify: msg;
		nextPut: msg</body>

<body package="SSL" selector="sendClientCertificateMessage:withCertificateChain:">sendClientCertificateMessage: aHandshake withCertificateChain: aCertificateChain

	| msg |
	msg := CertificateMessage certificateChain: aCertificateChain.
	aHandshake clientCertificate: msg; nextPut: msg</body>

<body package="SSL" selector="sendClientKeyExchange:">sendClientKeyExchange: aHandshake 
	self subclassResponsibility</body>

<body package="SSL" selector="sendServerCertificateMessage:withCertificateChain:">sendServerCertificateMessage: aHandshake withCertificateChain: aCertificateChain

	| msg |
	msg := CertificateMessage certificateChain: aCertificateChain.
	aHandshake serverCertificate: msg; nextPut: msg</body>

<body package="SSL" selector="sendServerKeyExchange:">sendServerKeyExchange: aHandshake

	self subclassResponsibility</body>

<body package="SSL" selector="serverKeyExchangeMessageClass">serverKeyExchangeMessageClass

	self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.SSLKeyExchange</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	self subclassResponsibility</body>
</methods>

<methods>
<class-id>Security.SSLBlockPadding</class-id> <category>private</category>

<body package="SSL" selector="detectPaddingIn:from:to:">detectPaddingIn: aByteArray from: start to: end

	^end - (aByteArray at: end) - 1</body>

<body package="SSL" selector="fillPaddingIn:from:to:">fillPaddingIn: aByteArray from: start to: end

	| padByte |
	padByte := end - start.
	start to: end do: [ :i |
		aByteArray at: i put: padByte ]</body>
</methods>

<methods>
<class-id>Security.SSLBlockPadding</class-id> <category>ssl</category>

<body package="SSL" selector="sslCipherName">sslCipherName

	^cipher sslCipherName</body>

<body package="SSL" selector="sslIVSize">sslIVSize

	^cipher sslIVSize</body>

<body package="SSL" selector="sslKeyMaterialSize">sslKeyMaterialSize

	^cipher sslKeyMaterialSize</body>
</methods>

<methods>
<class-id>Security.ChangeCipherSpecMessage</class-id> <category>accessing</category>

<body package="SSL" selector="protocol">protocol

	^20</body>
</methods>

<methods>
<class-id>Security.ChangeCipherSpecMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	aByteStream nextPut: 1</body>
</methods>

<methods>
<class-id>Security.ChangeCipherSpecMessage</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream nextPutAll: (#ChangeCipherSpec &lt;&lt; #security &gt;&gt; 'ChangeCipherSpec') asString</body>
</methods>

<methods>
<class-id>Security.ChangeCipherSpecMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| code |
	code := aByteStream next.
	code = 1 ifFalse: [
		SSLIllegalParameter new
			messageText: (
				(#InvalidCCSCode1s &lt;&lt; #security &gt;&gt; 'ChangeCipherSpec with wrong code &lt;1s&gt;')
					expandMacrosWith: code printString);
			parameter: code;
			raise ].
	^self new</body>
</methods>

<methods>
<class-id>Security.ClientHelloMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| cipherSuitesLength compressionLength compressions lengthOffset |
	lengthOffset := super readFrom: aByteStream in: aConnection.
	cipherSuitesLength := (aByteStream next bitShift: 8) + aByteStream next.
	"Remember all lengths are in bytes"
	cipherSuites := OrderedCollection new: (cipherSuitesLength bitShift: -1).
	(cipherSuitesLength bitShift: -1) timesRepeat: [
		cipherSuites add: (SSLCipherSuite readFrom: aByteStream in: aConnection) ].
	"Compression methods are not supported, so what's left in the stream should
	be list lenght of 1 and a single compression 0 indicating no compression"
	compressionLength := aByteStream next.
	compressions := OrderedCollection new: compressionLength.
	compressionLength timesRepeat: [
		compressions add: aByteStream next ].
	"Now let's check if the total length matches what we read so far"
	lengthOffset = (3 "lengths: ciphers(2)+compressions(1)" + cipherSuitesLength + compressionLength)
		ifFalse: [ SSLIllegalParameter new
				messageText: (
					(#InvalidCHLength1s &lt;&lt; #security &gt;&gt; 'Received client hello with mismatched message length &lt;1s&gt;')
						expandMacrosWith: lengthOffset printString);
				parameter: lengthOffset - cipherSuitesLength - compressionLength - 3;
				raise ].
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| length cipherSuitesLength |
	super writeOn: aByteStream in: aConnection.
	"Remember all lengths are in bytes"
	cipherSuitesLength := cipherSuites size bitShift: 1.
	length :=  4 "suites length(2)+compressions(2)" + cipherSuitesLength.
	super writeOn: aByteStream in: aConnection lengthOffset: length.
	aByteStream
		nextPut: (cipherSuitesLength bitShift: -8);
		nextPut: (cipherSuitesLength bitAnd: 255).
	cipherSuites do: [ :cs | cs writeOn: aByteStream in: aConnection ].
	"Compression methods are not supported, so the ususal thing is to make a list
	of lenght 1 with a single compression 0 indicating no compression"
	aByteStream
		nextPut: 1;
		nextPut: 0</body>
</methods>

<methods>
<class-id>Security.ClientHelloMessage</class-id> <category>initialization</category>

<body package="SSL" selector="major:minor:random:session:suites:">major: majVer minor: minVer random: ba session: id suites: ciphSuites

	super major: majVer minor: minVer random: ba session: id.
	cipherSuites := ciphSuites</body>
</methods>

<methods>
<class-id>Security.ClientHelloMessage</class-id> <category>accessing</category>

<body package="SSL" selector="cipherSuites">cipherSuites

	^cipherSuites</body>
</methods>

<methods>
<class-id>Security.ClientHelloMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="major:minor:random:session:suites:">major: majVer minor: minVer random: ba session: id suites: ciphSuites

	^self new major: majVer minor: minVer random: ba session: id suites: ciphSuites</body>

<body package="SSL" selector="major:minor:random:suites:">major: majVer minor: minVer random: ba suites: ciphSuites

	^self new major: majVer minor: minVer random: ba session: nil suites: ciphSuites</body>
</methods>

<methods>
<class-id>Security.ClientHelloMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^1</body>
</methods>

<methods>
<class-id>Security.ClientHello20Message</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection
"SSL3.0 Spec, Appendix E:
	uint8 V2CipherSpec[3];
	struct {
		unit8 msg_type;
		Version version;
		uint16 cipher_spec_length;
		uint16 session_id_length;
		uint16 challenge_length;
		V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
		opaque session_id[V2ClientHello.session_id_length];
		Random challenge;
	} V2ClientHello;"

	| cipherSuitesLength sessionIdLength challengeLength suiteNumber |
	(aByteStream next = 1) ifFalse: [ "Confirm we're reading ClientHello"
		SSLIllegalParameter raiseSignal: (
			#Unsupported20Message &lt;&lt; #security &gt;&gt; 'Received an SSL 2.0 message which is not a ClientHello!')].
	majorVersion := aByteStream next.
	minorVersion := aByteStream next.
	cipherSuitesLength := (aByteStream next bitShift: 8) + aByteStream next.
	sessionIdLength := (aByteStream next bitShift: 8) + aByteStream next.
	challengeLength := (aByteStream next bitShift: 8) + aByteStream next.
	suiteNumber := cipherSuitesLength // 3.
	cipherSuites := OrderedCollection new: suiteNumber.
	suiteNumber timesRepeat: [
		cipherSuites add: (SSLCipherSuite read20From: aByteStream in: aConnection) ].
	sessionId := sessionIdLength = 0
		ifTrue: [nil]
		ifFalse: [(aByteStream next: sessionIdLength) inject: 0 into: [ :t :b | t *256 + b ]].
	randomValue := aByteStream next: challengeLength</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| length |
	aByteStream
		nextPut: 1; "ClientHello type code"
		nextPut: majorVersion;
		nextPut: minorVersion.
	length := cipherSuites size * 3.
	aByteStream nextPut: (length bitShift: -8); nextPut: (length bitAnd: 255).
	length := sessionId isNil ifTrue: [0] ifFalse: [sessionId size].
	aByteStream nextPut: (length bitShift: -8); nextPut: (length bitAnd: 255).
	length := randomValue size.
	aByteStream nextPut: (length bitShift: -8); nextPut: (length bitAnd: 255).
	cipherSuites do: [ :cs | cs write20On: aByteStream in: aConnection ].
	sessionId isNil ifFalse: [aByteStream nextPutAll: sessionId asBigEndianByteArray].
	randomValue := aByteStream nextPutAll: randomValue</body>
</methods>

<methods>
<class-id>Security.ClientHello20Message</class-id> <category>accessing</category>

<body package="SSL" selector="randomValue">randomValue
"SSL 3.0 Spec, Appendix E:
The client's challenge to the server for the server to identify itself is a (nearly) arbitrary length random.  The Version 3.0 server will right justify the challenge data to become the ClientHello.random data (padded with leading zeroes, if necessary), as specified in this Version 3.0 protocol.  If the length of the challenge is greater than 32 bytes, then only the last 32 bytes are used.  It is legitimate (but not necessary) for a V3 server to reject a V2 ClientHello that has fewer than 16 bytes of challenge data."

	randomValue size &lt; 16 ifTrue: [
		SSLShort20Challenge new
			messageText: (#RandomTooShort &lt;&lt; #security &gt;&gt; 'Random value from 2.0 client is very short !');
			parameter: randomValue;
			raise].
	^randomValue size &lt; 32
		ifTrue: [ | val |
			val := ByteArray new: 32.
			val replaceFrom: 33 - randomValue size to: 32 with: randomValue.
			val ]
		ifFalse: [ randomValue size = 32
				ifTrue: [randomValue]
				ifFalse: [randomValue copyFrom: randomValue size - 31 to: randomValue size ]]</body>
</methods>

<methods>
<class-id>Security.SSLBadCertificate class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^42</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>accessing</category>

<body package="SSL" selector="allowesResumableSessions">allowesResumableSessions

	^parameters at: #shouldAllowResumableSessions ifAbsent: [ false ]</body>

<body package="SSL" selector="allowResumableSessions">allowResumableSessions

	parameters at: #shouldAllowResumableSessions put: true</body>

<body package="SSL" selector="certificate:key:">certificate: certificateOrChain key: key
"Adds a certificate and the corresponding private key that allows the receiver to authenticate itself.
	certificateOrChain	&lt;Certificate | SequenceableCollection of: Certificate&gt;	the certificate or chain starting with the receiver's certificate and ending with a CA certificate (optionally)
	key	&lt;RSAPrivateKey | DSAPrivateKey &gt;	the private key corresponding to the certificate
"
	| chain |
	chain := certificateOrChain isSequenceable ifTrue: [ certificateOrChain ] ifFalse: [ Array with: certificateOrChain ].
	chain first addChain: chain andKey: key toContext: self</body>

<body package="SSL" selector="certificateRegistry">certificateRegistry

	^certificateRegistry</body>

<body package="SSL" selector="ciphers">ciphers

	^ciphers</body>

<body package="SSL" selector="disallowResumableSessions">disallowResumableSessions

	parameters at: #shouldAllowResumableSessions put: false</body>

<body package="SSL" selector="majorVersion">majorVersion

	^3</body>

<body package="SSL" selector="minorVersion">minorVersion

	^0</body>

<body package="SSL" selector="random">random
"
	^&lt;DSSRandom&gt; a random generator to use for all PRNG operations
"
	^random ifNil: [ self class defaultRandom ]</body>

<body package="SSL" selector="random:">random: aRandom
"
	^&lt;DSSRandom&gt; a random generator to use for all PRNG operations
"
	random := aRandom</body>

<body package="SSL" selector="recognizedAuthorityNames">recognizedAuthorityNames

	^self certificateRegistry trustedCertificates collect: [ :cert | cert subject ]</body>

<body package="SSL" selector="trustedCertificates">trustedCertificates

	^certificateRegistry trustedCertificates</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>services</category>

<body package="SSL" selector="connectionFor:">connectionFor: aReadAppendByteStream

	^self
		connectionFor: aReadAppendByteStream
		using: (SSLSession newIn: self)</body>

<body package="SSL" selector="connectionFor:using:">connectionFor: aReadAppendByteStream using: aSession

	^SSLConnection newFor: aReadAppendByteStream in: aSession</body>

<body package="SSL" selector="disallowToResume:">disallowToResume: aSession

	^sessions
		removeKey: aSession id
		ifAbsent: []</body>

<body package="SSL" selector="newIdForSession:">newIdForSession: aSession

	^self allowesResumableSessions
		ifTrue: [ | id |
			id := self newSessionId.
			sessions at: id put: aSession.
			id ]
		ifFalse: [ nil ]</body>

<body package="SSL" selector="newSessionId">newSessionId

	^(lastSessionId := lastSessionId + 1) asBigEndianByteArray</body>

<body package="SSL" selector="sessionForId:">sessionForId: id

	^sessions at: id ifAbsent: [ nil ]</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>initialization</category>

<body package="SSL" selector="initialize">initialize

	sessions := Dictionary new.
	lastSessionId := 0.
	parameters := Dictionary new.</body>

<body package="SSL" selector="initializeSuites:">initializeSuites: theCipherSuites

	self initializeSuites: theCipherSuites registry: Security.X509.X509Registry default</body>

<body package="SSL" selector="initializeSuites:registry:">initializeSuites: theCipherSuites registry: aRegistry

	self initialize.
	ciphers := theCipherSuites.
	certificateRegistry := aRegistry</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>handshaking</category>

<body package="SSL" selector="validateCertificateChain:for:">validateCertificateChain: aCertificateChain for: aHandshake

	| sslEx |
	[	[[[[[	certificateRegistry validateCertificateChain: aCertificateChain
		]	on: Security.X509.BadCertificate, Security.X509.RootNotTrusted, Security.X509.BadCACertificate
			do: [ :ex |
				sslEx := SSLBadCertificate replacementFor: ex.
				ex resignalAs: sslEx ]
		]	on: Security.X509.ValidityError do: [ :ex |
				sslEx := SSLCertificateExpired replacementFor: ex.
				ex resignalAs: sslEx ]
		]	on: Security.X509.Revoked do: [ :ex |
				sslEx := SSLCertificateRevoked replacementFor: ex.
				ex resignalAs: sslEx ]
		]	on: Security.X509.Unsupported do: [ :ex |
				sslEx := SSLUnsupportedCertificate replacementFor: ex.
				ex resignalAs: sslEx ]
		]	on: Security.X509.X509Error do: [ :ex |
				sslEx := SSLCertificateUnknown replacementFor: ex.
				ex resignalAs: sslEx ]
	] ifCurtailed: [ aHandshake sendMessage: sslEx alertMessage ]</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>accessing - certificates</category>

<body package="SSL" selector="addValidCertificate:">addValidCertificate: anX509Certificate

	validCertificates isNil ifTrue: [validCertificates := Dictionary new].
	validCertificates
		at: anX509Certificate subject asAssociations
		put: anX509Certificate</body>

<body package="SSL" selector="isKnownValidCertificate:">isKnownValidCertificate: anX509Certificate

	validCertificates isNil ifTrue: [^false].
	^(	validCertificates at: anX509Certificate subject asAssociations ifAbsent: [ ^false ]
	)	derCertificate = anX509Certificate derCertificate</body>

<body package="SSL" selector="removeValidCertificate:">removeValidCertificate: anX509Certificate

	| key |
	key := anX509Certificate subject asAssociations.
	^validCertificates isNil
		ifTrue: [ (KeyNotFoundError receiver: self selector: #removeKey: index: key) raiseRequest ]
		ifFalse: [ validCertificates removeKey: key ]</body>

<body package="SSL" selector="supportedCertificateTypes">supportedCertificateTypes
"Let's make everything that we support the default. At the moment it's just RSA certificates. The type names are defined in the CertificateRequestMessage."

	^parameters at: #certificateTypes ifAbsentPut: [ #(rsa dsa) ]</body>

<body package="SSL" selector="supportedCertificateTypes:">supportedCertificateTypes: aTypeCodeCollection
"Set the collection of supported certificate types. The type names are defined in the CertificateRequestMessage."

	^parameters at: #certificateTypes put: aTypeCodeCollection</body>

<body package="SSL" selector="validCertificateFor:">validCertificateFor: aDNAssociations

	validCertificates isNil ifTrue: [^nil].
	^validCertificates at: aDNAssociations ifAbsent: [ nil ]</body>
</methods>

<methods>
<class-id>Security.SSLContext</class-id> <category>accessing - keys</category>

<body package="SSL" selector="certificateCompatibleWith:">certificateCompatibleWith: aCertificateRequest
"A compatible certificate must be of one of the certificateTypes and it has to be signed (transitively ?) by one of the specified authorityNames"

	| certPair supported requested |
	supported := self supportedCertificateTypes.
	requested := aCertificateRequest certificateTypes
				select: [ :t | supported includes: t ].
	requested
		detect: [ :t |
			certPair := t = #rsa
				ifTrue: [ self rsaSigningCertificatePair ]
				ifFalse: [ self perform: (t, 'CertificatePair') asSymbol ].
			certPair notNil ]
		ifNone: [ nil ].
	^certPair
	"OK, this is pretty much useless until we have DN read/write support, so let's just skip it for now.
	^certPair isNil
		ifTrue: [nil]
		ifFalse: [ | certIssuer |
			certIssuer := certPair first last issuer asAssociations.
			(	aCertificateRequest authorityNames isEmpty or: [ 
					( aCertificateRequest authorityNames
						detect: [ :ca | certIssuer = ca asAssociations ]
						ifNone: [ nil ]
					) notNil ] )
				ifTrue: [certPair]
				ifFalse: [nil] ]"</body>

<body package="SSL" selector="dhKeyPair">dhKeyPair

	^parameters at: 'DHKP' ifAbsent: [nil]</body>

<body package="SSL" selector="dhKeyPair:">dhKeyPair: anArrayWithPublicAndPrivateKey
"The first item is expected to be an array consisting of values p, g, and y consecutively.
the second item is the private value x. See DH for definition of these values."

	^parameters at: 'DHKP' put: anArrayWithPublicAndPrivateKey</body>

<body package="SSL" selector="dhParameters">dhParameters

	^parameters at: 'DHPARAMS' ifAbsent: [nil]</body>

<body package="SSL" selector="dhParameters:">dhParameters: anArrayWithPAndG
"See DH for definition of the P and G values"

	^parameters at: 'DHPARAMS' put: anArrayWithPAndG</body>

<body package="SSL" selector="dsaCertificatePair">dsaCertificatePair

	^parameters at: 'DSSCP' ifAbsent: [nil]</body>

<body package="SSL" selector="dsaCertificatePair:">dsaCertificatePair: aCertificateChainAndPKArray

	^parameters at: 'DSSCP' put: aCertificateChainAndPKArray</body>

<body package="SSL" selector="dsaDHCertificatePair">dsaDHCertificatePair

	^parameters
		at: 'DSSDHCP'
		ifAbsent: [ self dsaCertificatePair ]</body>

<body package="SSL" selector="dsaDHCertificatePair:">dsaDHCertificatePair: aCertificateChainAndPKArray

	^parameters at: 'DSSDHCP' put: aCertificateChainAndPKArray</body>

<body package="SSL" selector="rsaCertificatePair">rsaCertificatePair

	^parameters at: 'RSACP' ifAbsent: [nil]</body>

<body package="SSL" selector="rsaCertificatePair:">rsaCertificatePair: aCertificateChainAndPKArray

	^parameters at: 'RSACP' put: aCertificateChainAndPKArray</body>

<body package="SSL" selector="rsaDHCertificatePair">rsaDHCertificatePair

	^parameters
		at: 'RSADHCP'
		ifAbsent: [ self rsaSigningCertificatePair ]</body>

<body package="SSL" selector="rsaDHCertificatePair:">rsaDHCertificatePair: aCertificateChainAndPKArray

	^parameters at: 'RSADHCP' put: aCertificateChainAndPKArray</body>

<body package="SSL" selector="rsaKeyPair">rsaKeyPair

	^parameters at: 'RSAKP' ifAbsent: [nil]</body>

<body package="SSL" selector="rsaKeyPair:">rsaKeyPair: anArrayWithPublicAndPrivateKey
"The first item is expected to be public key and the second private key"

	^parameters at: 'RSAKP' put: anArrayWithPublicAndPrivateKey</body>

<body package="SSL" selector="rsaSigningCertificatePair">rsaSigningCertificatePair

	^parameters at: 'RSASIGNCP' ifAbsent: [nil]</body>

<body package="SSL" selector="rsaSigningCertificatePair:">rsaSigningCertificatePair: aCertificateChainAndPKArray

	^parameters at: 'RSASIGNCP' put: aCertificateChainAndPKArray</body>
</methods>

<methods>
<class-id>Security.SSLContext class</class-id> <category>instance creation</category>

<body package="SSL" selector="newWithAllCipherSuites">newWithAllCipherSuites

	^self suites: self allCipherSuites</body>

<body package="SSL" selector="newWithAllCipherSuitesUsing:">newWithAllCipherSuitesUsing: aCertificateRegistry

	^self suites: self allCipherSuites registry: aCertificateRegistry</body>

<body package="SSL" selector="newWithSecureCipherSuites">newWithSecureCipherSuites

	^self suites: self secureCipherSuites</body>

<body package="SSL" selector="newWithSecureCipherSuitesUsing:">newWithSecureCipherSuitesUsing: aCertificateRegistry

	^self suites: self secureCipherSuites registry: aCertificateRegistry</body>

<body package="SSL" selector="suites:">suites: theCipherSuites

	^self new initializeSuites: theCipherSuites</body>

<body package="SSL" selector="suites:registry:">suites: theCipherSuites registry: aCertificateRegistry

	^self new initializeSuites: theCipherSuites registry: aCertificateRegistry</body>
</methods>

<methods>
<class-id>Security.SSLContext class</class-id> <category>constants</category>

<body package="SSL" selector="allCipherSuites">allCipherSuites
"All cipher suites that we support"

	^self secureCipherSuites, self weakCipherSuites</body>

<body package="SSL" selector="secureCipherSuites">secureCipherSuites
"Secure cipher suites that we support"

	^#(	SSL_RSA_WITH_RC4_128_SHA
		SSL_RSA_WITH_RC4_128_MD5
		SSL_RSA_WITH_DES_CBC_SHA
		SSL_DHE_RSA_WITH_DES_CBC_SHA
		SSL_DHE_DSS_WITH_DES_CBC_SHA
		SSL_RSA_WITH_3DES_EDE_CBC_SHA
		SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
		SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
	)	collect: [ :sel |
		SSLCipherSuite perform: sel ]</body>

<body package="SSL" selector="weakCipherSuites">weakCipherSuites
"Cipher suites that do not encrypt or do not authenticate"

	^#(	SSL_DH_anon_WITH_RC4_128_MD5
		SSL_DH_anon_WITH_DES_CBC_SHA
		SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
		SSL_RSA_WITH_NULL_SHA
		SSL_RSA_WITH_NULL_MD5
		SSL_NULL_WITH_NULL_NULL
	) collect: [ :sel |
		SSLCipherSuite perform: sel ]</body>
</methods>

<methods>
<class-id>Security.SSLContext class</class-id> <category>accessing</category>

<body package="SSL" selector="defaultRandom">defaultRandom
"
	^&lt;DSSRandom&gt; a random generator to use for all PRNG operations
"
	^defaultRandom ifNil: [ self defaultRandomValue ]</body>

<body package="SSL" selector="defaultRandom:">defaultRandom: random
"
	random &lt;DSSRandom&gt; a random generator to use for all PRNG operations
"
	defaultRandom := random</body>

<body package="SSL" selector="defaultRandomValue">defaultRandomValue

	^DSSRandom default</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec</class-id> <category>services</category>

<body package="SSL" selector="clone">clone

	| name |
	name := self printString.
	^self class perform: (
		name first = $3
			ifTrue: [ #ThreeDES_EDE_CBC_SHA ]
			ifFalse: [ name asSymbol ])</body>

<body package="SSL" selector="digest:">digest: aByteArray
"Apply the mac function to aByteArray"

	^mac byteHash: aByteArray</body>

<body package="SSL" selector="digestStream:">digestStream: aFragmentStream
"Apply the mac function to aByteArray"

	^mac byteHashStream: aFragmentStream</body>

<body package="SSL" selector="isEncrypting">isEncrypting

	^bulkCipher notNil</body>

<body package="SSL" selector="isSigning">isSigning

	^mac notNil</body>

<body package="SSL" selector="macPaddingSize">macPaddingSize

	^mac sslPaddingSize</body>

<body package="SSL" selector="signingPad1:">signingPad1: macSecret

	signingPad1 isNil ifTrue: [
		signingPad1 :=
			ByteArray new: (
				macSecret size "mac secret size = hash size"
				+ self macPaddingSize "padding size = 48(MD5) or 40(SHA)"
				+ 11 "sequence number length + type + length size").
		(WriteStream on: signingPad1)
			nextPutAll: macSecret;
			nextPutAll: mac sslPadding1].
	^signingPad1</body>

<body package="SSL" selector="signingPad2:">signingPad2: macSecret

	signingPad2 isNil ifTrue: [
		signingPad2 :=
			ByteArray new: (
				macSecret size "mac secret size = hash size"
				+ self macPaddingSize "padding size = 48(MD5) or 40(SHA)"
				+ self hashSize "inner hash size").
		(WriteStream on: signingPad2)
			nextPutAll: macSecret;
			nextPutAll: mac sslPadding2].
	^signingPad2</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec</class-id> <category>accessing</category>

<body package="SSL" selector="bulkCipher">bulkCipher

	^bulkCipher</body>

<body package="SSL" selector="bulkCipherName">bulkCipherName

	^bulkCipher isNil ifTrue: ['NULL'] ifFalse: [bulkCipher sslCipherName]</body>

<body package="SSL" selector="hashSize">hashSize

	^mac isNil ifTrue: [0] ifFalse: [mac hashSize]</body>

<body package="SSL" selector="ivSize">ivSize

	^bulkCipher isNil ifTrue: [0] ifFalse: [bulkCipher sslIVSize]</body>

<body package="SSL" selector="keySize">keySize

	^bulkCipher isNil ifTrue: [0] ifFalse: [bulkCipher sslKeyMaterialSize]</body>

<body package="SSL" selector="mac">mac

	^mac</body>

<body package="SSL" selector="macName">macName

	^mac isNil ifTrue: ['NULL'] ifFalse: [mac sslMacName]</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec</class-id> <category>initialization</category>

<body package="SSL" selector="DES_CBC_SHA">DES_CBC_SHA

	mac := self SHA.
	bulkCipher := self DES_CBC</body>

<body package="SSL" selector="initializeBulkCipherWithKey:andIV:">initializeBulkCipherWithKey: keyByteArray andIV: ivByteArray

	bulkCipher notNil ifTrue: [
		bulkCipher setKey: keyByteArray.
		ivByteArray isEmpty ifFalse: [
			bulkCipher setIV: ivByteArray copy ] ]</body>

<body package="SSL" selector="NULL_MD5">NULL_MD5

	mac := self MD5.
	bulkCipher := nil.</body>

<body package="SSL" selector="NULL_NULL">NULL_NULL

	mac := nil.
	bulkCipher := nil</body>

<body package="SSL" selector="NULL_SHA">NULL_SHA

	mac := self SHA.
	bulkCipher := nil</body>

<body package="SSL" selector="RC4_128_MD5">RC4_128_MD5

	mac := self MD5.
	bulkCipher := self RC4_128</body>

<body package="SSL" selector="RC4_128_SHA">RC4_128_SHA

	mac := self SHA.
	bulkCipher := self RC4_128</body>

<body package="SSL" selector="ThreeDES_EDE_CBC_SHA">ThreeDES_EDE_CBC_SHA

	mac := self SHA.
	bulkCipher := self ThreeDES_EDE_CBC</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec</class-id> <category>algorithms</category>

<body package="SSL" selector="DES_CBC">DES_CBC

	^SSLBlockPadding on: DES newCBC</body>

<body package="SSL" selector="MD5">MD5

	^MD5 new</body>

<body package="SSL" selector="RC4_128">RC4_128

	^ARC4 new</body>

<body package="SSL" selector="SHA">SHA

	^SHA new</body>

<body package="SSL" selector="ThreeDES_EDE_CBC">ThreeDES_EDE_CBC

	^SSLBlockPadding on: DES new3EDE_CBC</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream
		nextPutAll: self bulkCipherName;
		nextPut: $_;
		nextPutAll: self macName</body>
</methods>

<methods>
<class-id>Security.SSLCipherSpec class</class-id> <category>instance creation</category>

<body package="SSL" selector="DES_CBC_SHA">DES_CBC_SHA

	^self new DES_CBC_SHA</body>

<body package="SSL" selector="null">null

	^self NULL_NULL</body>

<body package="SSL" selector="NULL_MD5">NULL_MD5

	^self new NULL_MD5</body>

<body package="SSL" selector="NULL_NULL">NULL_NULL

	^self new NULL_NULL</body>

<body package="SSL" selector="NULL_SHA">NULL_SHA

	^self new NULL_SHA</body>

<body package="SSL" selector="RC4_128_MD5">RC4_128_MD5

	^self new RC4_128_MD5</body>

<body package="SSL" selector="RC4_128_SHA">RC4_128_SHA

	^self new RC4_128_SHA</body>

<body package="SSL" selector="ThreeDES_EDE_CBC_SHA">ThreeDES_EDE_CBC_SHA

	^self new ThreeDES_EDE_CBC_SHA</body>
</methods>

<methods>
<class-id>Security.SSLCertificateRevoked class</class-id> <category>accessing</category>

<body package="SSL" selector="alertCode">alertCode

	^44</body>
</methods>

<methods>
<class-id>Security.SecretMaterialStream</class-id> <category>initialization</category>

<body package="SSL" selector="initializeSecret:">initializeSecret: aSecret

	secret := aSecret</body>
</methods>

<methods>
<class-id>Security.SecretMaterialStream</class-id> <category>accessing</category>

<body package="SSL" selector="secret">secret

	^secret</body>
</methods>

<methods>
<class-id>Security.SecretMaterialStream class</class-id> <category>instance creation</category>

<body package="SSL" selector="forSecret:">forSecret: aSecret

	^(self onFragment: nil)
		initializeSecret: aSecret;
		yourself</body>
</methods>

<methods>
<class-id>Security.FinishedMessage</class-id> <category>initialization</category>

<body package="SSL" selector="md5Hash:shaHash:">md5Hash: md5BA shaHash: shaBA

	md5Hash := md5BA.
	shaHash := shaBA</body>
</methods>

<methods>
<class-id>Security.FinishedMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	md5Hash := aByteStream next: 16.
	shaHash := aByteStream next: 20.
	length = (36 "MD5(16)+SHA(20)") ifFalse: [
		SSLIllegalParameter new
			messageText: ((#InvalidFLength &lt;&lt; #security &gt;&gt; 'Received finished with wrong message length &lt;1s&gt;')
				expandMacrosWith: length printString);
			parameter: length;
			raise ].
	^self</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	super writeOn: aByteStream in: aConnection.
	self writeByteLength: 36 "MD5(16)+SHA(20)" on: aByteStream in: aConnection.
	aByteStream
		nextPutAll: md5Hash;
		nextPutAll: shaHash</body>
</methods>

<methods>
<class-id>Security.FinishedMessage</class-id> <category>accessing</category>

<body package="SSL" selector="md5Hash">md5Hash

	^md5Hash</body>

<body package="SSL" selector="shaHash">shaHash

	^shaHash</body>
</methods>

<methods>
<class-id>Security.FinishedMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="md5Hash:shaHash:">md5Hash: md5BA shaHash: shaBA

	^self new md5Hash: md5BA shaHash: shaBA</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.FinishedMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^20</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange</class-id> <category>testing</category>

<body package="SSL" selector="isAnonymous">isAnonymous

	^type = #DH_anon</body>

<body package="SSL" selector="isEphemeral">isEphemeral

	^type = #DHE</body>

<body package="SSL" selector="isFixed">isFixed

	^type = #DH</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange</class-id> <category>handshaking</category>

<body package="SSL" selector="clientKeyExchangeMessageClass">clientKeyExchangeMessageClass

	^ClientDHKeyExchangeMessage</body>

<body package="SSL" selector="receiveClientKeyExchange:">receiveClientKeyExchange: aHandshake

	| dhCert pms |
	super receiveClientKeyExchange: aHandshake.
	dhCert := false.
	key := aHandshake clientKeyExchange yc ifNil: [
			self isFixed
				ifTrue: [ dhCert := true.
					self error: (#FixedDHUnsupported5 &lt;&lt; #security &gt;&gt; 'Need to confirm compatibility of the certificate parameters !').
					self error: (#FixedDHUnsupported &lt;&lt; #security &gt;&gt; 'Need to dig out the client key from the certificate !') ]
				ifFalse: [ SSLHandshakeFailure new
						messageText: (
							(#ClientKeyMissing &lt;&lt; #security &gt;&gt; 'Client failed to provide a public key for &lt;1s&gt;')
								expandMacrosWith: self printString);
						parameter: self;
						sendIn: aHandshake ] ].
	pms := self computeSharedSecretBytesUsing: key.
	aHandshake generateMasterSecretFrom: pms.
	(aHandshake clientAuthenticates and: [ dhCert not ]) ifTrue: [
		self receiveCertificateVerify: aHandshake ]</body>

<body package="SSL" selector="receiveServerKeyExchange:">receiveServerKeyExchange: aHandshake

	| msg |
	msg := aHandshake next.
	(self isAnonymous and: [ msg class = ServerDHKeyExchangeMessage ]) ifTrue: [
		dh := DH p: msg p g: msg g.
		key := msg ys.
		^aHandshake serverKeyExchange: msg; next ].
	(msg isKindOf: CertificateMessage) ifTrue: [
		aHandshake
			validateCertificateChain: msg certificateChain;
			serverCertificate: msg.
		self isFixed ifTrue: [
			self error: (#FixedDHUnsupported4 &lt;&lt; #security &gt;&gt; 'Getting the parameters from a DH certificate should go here !').
			^aHandshake next].
		msg := aHandshake next.
		(msg class = ServerDHKeyExchangeMessage) ifTrue: [
			aHandshake
				verifyKeyExchageMessageSignature: msg;
				serverKeyExchange: msg.
			dh := DH p: msg p g: msg g.
			key := msg ys.
			^aHandshake next ] ].
	^aHandshake unexpectedMessage: msg</body>

<body package="SSL" selector="sendClientKeyExchange:">sendClientKeyExchange: aHandshake 
	| msg cp pms |
	self isFixed ifTrue: [
		(type = #RSA
			ifTrue: [ aHandshake context rsaDHCertificatePair ]
			ifFalse: [ aHandshake context dsaDHCertificatePair ]
		) ifNotNil: [ :dhcp |
			self error: (#FixedDHUnsupported2 &lt;&lt; #security &gt;&gt; 'Need to verify compatiblity of DH parameters').
			"server ones should be in dh and the client ones in the certificate"
			self sendClientCertificateMessage: aHandshake withCertificateChain: dhcp first.
			self error: (#FixedDHUnsupported3 &lt;&lt; #security &gt;&gt; 'Need to stuff the private&amp;public values into the dh instance !').
			^self computeSharedSecretBytesUsing: key ] ].
	aHandshake shouldAuthenticateClient ifTrue: [
		(cp := aHandshake compatibleClientCertificate) isNil
			ifTrue: [ aHandshake nextPut: AlertMessage no_certificate ]
			ifFalse: [self
					sendClientCertificateMessage: aHandshake
					withCertificateChain: cp first ]].
	msg := ClientDHKeyExchangeMessage yc: dh publicValue.
	aHandshake
		clientKeyExchange: msg;
		nextPut: msg.
	pms := self computeSharedSecretBytesUsing: key.
	aHandshake generateMasterSecretFrom: pms.
	"If client sends a signing certificate, it has to send a verification that it owns the private key for it."
	cp notNil ifTrue: [
		self sendCertificateVerify: aHandshake usingKey: cp last ]</body>

<body package="SSL" selector="sendServerKeyExchange:">sendServerKeyExchange: aHandshake

	| cp |
	self isAnonymous ifTrue: [
		"Anonymous handshake skips Certificate and sends just a ServerKeyExchange"
		^self sendServerKeyExchangeMessage: aHandshake signedWith: nil ].
	self isFixed ifTrue: [
		cp := signing = #RSA
				ifTrue: [ aHandshake context rsaDHCertificatePair ]
				ifFalse: [ aHandshake context dsaDHCertificatePair ].
		^cp isNil
			ifTrue: [ SSLHandshakeFailure new
					messageText: (
						(#NoSuitableCert1s &lt;&lt; #security &gt;&gt; 'No suitable certificate for &lt;1s&gt;')
							expandMacrosWith: self printString);
					parameter: self;
					sendIn: aHandshake ]
			ifFalse: [ self sendServerCertificateMessage: aHandshake withCertificateChain: cp first.
				self error: (#FixedDHUnsupported1 &lt;&lt; #security &gt;&gt; 'Need to create a dh instance initialized from the cp !') ] ].
	cp := signing = #RSA
			ifTrue: [ aHandshake context rsaSigningCertificatePair ]
			ifFalse: [ aHandshake context dsaCertificatePair ].
	cp isNil ifTrue: [
		^SSLNoServerCertificate new
			messageText: (#NoSuitableCert &lt;&lt; #security &gt;&gt; 'No suitable certificate for chosen key exchange !');
			parameter: self;
			sendIn: aHandshake as: AlertMessage handshake_failure ].
	self
		sendServerCertificateMessage: aHandshake withCertificateChain: cp first;
		sendServerKeyExchangeMessage: aHandshake signedWith: cp last</body>

<body package="SSL" selector="sendServerKeyExchangeMessage:signedWith:">sendServerKeyExchangeMessage: aHandshake signedWith: aPrivateKey

	| msg kp |
	dh := (kp := aHandshake context dhKeyPair) isNil
			ifTrue: [ ((kp := aHandshake context dhParameters) isNil
						ifTrue: [ SSLNoDHParameters new
								messageText: (#NoDHParams &lt;&lt; #security &gt;&gt; 'No DH parameters. Proceed to generate (may take a while) !');
								sendIn: aHandshake as: AlertMessage handshake_failure .
							DH new ]
						ifFalse: [ DH p: kp first g: kp last ])
				 	publicValue;
					yourself ]
			ifFalse: [ (DH p: (kp first at: 1) g: (kp first at: 2))
					x: kp last y: kp first last;
					yourself ].
	msg := ServerDHKeyExchangeMessage
			p: dh p
			g: dh g
			ys: dh y.
	aHandshake signKeyExchangeMessage: msg key: aPrivateKey.
	aHandshake serverKeyExchange: msg; nextPut: msg</body>

<body package="SSL" selector="serverKeyExchangeMessageClass">serverKeyExchangeMessageClass

	^ServerDHKeyExchangeMessage</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange</class-id> <category>initialization</category>

<body package="SSL" selector="initializeAnonymous">initializeAnonymous

	type := #DH_anon</body>

<body package="SSL" selector="initializeEphemeralDSS">initializeEphemeralDSS

	type := #DHE.
	signing := #DSS</body>

<body package="SSL" selector="initializeEphemeralRSA">initializeEphemeralRSA

	type := #DHE.
	signing := #RSA</body>

<body package="SSL" selector="initializeFixedDSS">initializeFixedDSS

	type := #DH.
	signing := #DSS</body>

<body package="SSL" selector="initializeFixedRSA">initializeFixedRSA

	type := #DH.
	signing := #RSA</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream nextPutAll: type.
	signing notNil ifTrue: [
		aStream nextPut: $_;
			nextPutAll: signing ].</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange</class-id> <category>private</category>

<body package="SSL" selector="computeSharedSecretBytesUsing:">computeSharedSecretBytesUsing: aPublicKey

	^(dh sharedSecretUsing: aPublicKey)
		asBigEndianByteArrayPaddedTo: dh p digitLength</body>
</methods>

<methods>
<class-id>Security.SSLDHKeyExchange class</class-id> <category>instance creation</category>

<body package="SSL" selector="anonymous">anonymous

	^self new initializeAnonymous</body>

<body package="SSL" selector="ephemeralDSS">ephemeralDSS

	^self new initializeEphemeralDSS</body>

<body package="SSL" selector="ephemeralRSA">ephemeralRSA

	^self new initializeEphemeralRSA</body>

<body package="SSL" selector="fixedDSS">fixedDSS

	^self new initializeFixedDSS</body>

<body package="SSL" selector="fixedRSA">fixedRSA

	^self new initializeFixedRSA</body>
</methods>

<methods>
<class-id>Security.CertificateMessage</class-id> <category>reading/writing</category>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	| length chainLength |
	length := self readByteLengthFrom: aByteStream in: aConnection.
	chainLength := self readByteLengthFrom: aByteStream in: aConnection.
	length = (chainLength + 3) ifFalse: [
		SSLIllegalParameter new
			messageText: (#InvalidCLength &lt;&lt; #security &gt;&gt; 'Message length and certificate chain length mismatch');
			parameter: length - chainLength;
			raise ].
	certificateChain := OrderedCollection new.
	[ chainLength &gt; 0 ] whileTrue: [ | certLength |
		certLength := self readByteLengthFrom: aByteStream in: aConnection.
		certificateChain add: (Security.X509.Certificate fromBytes: (aByteStream next: certLength)).
		chainLength := chainLength - certLength - 3 "have to subtract certLenght bytes as well" ]</body>

<body package="SSL" selector="writeOn:in:">writeOn: aByteStream in: aConnection

	| chainLength |
	super writeOn: aByteStream in: aConnection.
	chainLength := certificateChain inject: 0 into: [ :t :c | t + c derCertificate size + 3 "cert len bytes" ].
	self writeByteLength: 3 "chainLength" + chainLength on: aByteStream in: aConnection.
	self writeByteLength: chainLength on: aByteStream in: aConnection.
	certificateChain do: [ :c |
		self writeByteLength: c derCertificate size on: aByteStream in: aConnection.
		aByteStream nextPutAll: c derCertificate ]</body>
</methods>

<methods>
<class-id>Security.CertificateMessage</class-id> <category>initialization</category>

<body package="SSL" selector="certificateChain:">certificateChain: aCertificateChain

	certificateChain := aCertificateChain</body>
</methods>

<methods>
<class-id>Security.CertificateMessage</class-id> <category>accessing</category>

<body package="SSL" selector="certificateChain">certificateChain

	^certificateChain</body>

<body package="SSL" selector="isRSA">isRSA

	^certificateChain first isRSA</body>

<body package="SSL" selector="publicKey">publicKey

	^certificateChain first publicKey</body>
</methods>

<methods>
<class-id>Security.CertificateMessage class</class-id> <category>instance creation</category>

<body package="SSL" selector="certificateChain:">certificateChain: aCertificateChain

	^self new certificateChain: aCertificateChain</body>

<body package="SSL" selector="readFrom:in:">readFrom: aByteStream in: aConnection

	^self new readFrom: aByteStream in: aConnection</body>
</methods>

<methods>
<class-id>Security.CertificateMessage class</class-id> <category>message types</category>

<body package="SSL" selector="type">type

	^11</body>
</methods>

<methods>
<class-id>Security.SSLRSAKeyExchange</class-id> <category>handshaking</category>

<body package="SSL" selector="clientKeyExchangeMessageClass">clientKeyExchangeMessageClass

	^ClientRSAKeyExchangeMessage</body>

<body package="SSL" selector="receiveClientKeyExchange:">receiveClientKeyExchange: aHandshake

	| pms |
	super receiveClientKeyExchange: aHandshake.
	pms := aHandshake clientKeyExchange preMasterSecretUsingPrivateKey: key.
	aHandshake rsaCheckClientVersionInPremasterSecret: pms.
	aHandshake generateMasterSecretFrom: pms.
	aHandshake clientAuthenticates ifTrue: [
		self receiveCertificateVerify: aHandshake]</body>

<body package="SSL" selector="receiveServerKeyExchange:">receiveServerKeyExchange: aHandshake

	| msg |
	msg := aHandshake next.
	(msg isKindOf: CertificateMessage) ifTrue: [
		aHandshake
			validateCertificateChain: msg certificateChain;
			serverCertificate: msg.
		key := msg publicKey.
		msg := aHandshake next ].
	(msg class = ServerRSAKeyExchangeMessage) ifTrue: [
		aHandshake
			verifyKeyExchageMessageSignature: msg;
			serverKeyExchange: msg.
		key := msg publicKey.
		msg := aHandshake next ].
	^msg</body>

<body package="SSL" selector="sendClientKeyExchange:">sendClientKeyExchange: aHandshake 
	| pms msg cp |
	aHandshake serverAuthenticates 
		ifTrue: [aHandshake shouldAuthenticateClient ifTrue: [
				(cp := aHandshake compatibleClientCertificate) notNil 
					ifTrue: [self
							sendClientCertificateMessage: aHandshake
							withCertificateChain: cp first]
					ifFalse: [aHandshake nextPut: AlertMessage no_certificate]]]
		ifFalse: [aHandshake connection session shouldPeerAuthenticate ifTrue: [
				SSLHandshakeFailure new
					messageText: (#ServerCertMissing &lt;&lt; #security &gt;&gt; 'Server did not provide a certificate !');
					sendIn: aHandshake]].
	pms := aHandshake generatePreMasterSecret.
	aHandshake generateMasterSecretFrom: pms.
	msg := ClientRSAKeyExchangeMessage
			decryptedPremasterSecret: pms
			usingPublicKey: key.
	aHandshake
		clientKeyExchange: msg;
		nextPut: msg.
	"If client sends a certificate, it has to send a verification that it owns the private key for it."
	cp notNil ifTrue: [
		self sendCertificateVerify: aHandshake usingKey: cp last ].</body>

<body package="SSL" selector="sendServerKeyExchange:">sendServerKeyExchange: aHandshake

	| kp cp |
	(cp := aHandshake context rsaCertificatePair) isNil
		ifTrue: [ "In this case there's no certificate with an encryption key matching the cipherSuite"
			(cp := aHandshake context rsaSigningCertificatePair) isNil
				ifTrue: [ "If there's not even a signing certificate, then we can't authenticate"
					SSLNoServerCertificate new
						messageText: (#NoSuitableCert &lt;&lt; #security &gt;&gt; 'No suitable certificate for chosen key exchange !');
						parameter: self;
						sendIn: aHandshake as: AlertMessage handshake_failure.
					"This is not quite standard, but allows to perform an anonymous key exchange
					even though the chosen cipher suite is not an anonymous type. It has to be
					explicitly approved by resuming the SSLNoServerCertificate warning though,
					which should protect the user from allowing it by mistake.
					Anonymous key exchanges are discussed in section F.1.1.1 of the SSL 3.0 Spec"
					kp := self sendServerKeyExchangeMessage: aHandshake signedWith: nil ]
				ifFalse: [ "If there's just a signing certificate we have to send both
					a Certificate and a signed ServerKeyExchange messages."
					self sendServerCertificateMessage: aHandshake withCertificateChain: cp first.
					kp := self sendServerKeyExchangeMessage: aHandshake signedWith: cp last ] ]
		ifFalse: [ "We've got a certificate with a key for encryption, so we send just the Certificate"
			self sendServerCertificateMessage: aHandshake withCertificateChain: cp first ].
	key := kp isNil
			ifTrue: [ cp last ]
			ifFalse: [ kp last ]</body>

<body package="SSL" selector="sendServerKeyExchangeMessage:signedWith:">sendServerKeyExchangeMessage: aHandshake signedWith: aPrivateKey

	| msg kp public |
	kp := aHandshake context rsaKeyPair.
	kp isNil ifTrue: [
		SSLHandshakeFailure new
			messageText: (#NoSuitableKeys &lt;&lt; #security &gt;&gt; 'No keys for chosen type of key exchange !');
			parameter: self;
			sendIn: aHandshake ].
	public := kp first.
	msg := ServerRSAKeyExchangeMessage
		modulus: public n
		exponent: public e.
	aHandshake signKeyExchangeMessage: msg key: aPrivateKey.
	aHandshake serverKeyExchange: msg; nextPut: msg.
	^kp</body>

<body package="SSL" selector="serverKeyExchangeMessageClass">serverKeyExchangeMessageClass

	^ServerRSAKeyExchangeMessage</body>
</methods>

<methods>
<class-id>Security.SSLRSAKeyExchange</class-id> <category>printing</category>

<body package="SSL" selector="printOn:">printOn: aStream

	aStream nextPutAll: 'RSA'</body>
</methods>

<methods>
<class-id>Security.X509.Certificate</class-id> <category>ssl</category>

<body package="SSL" selector="addChain:andKey:toContext:">addChain: chain andKey: key toContext: context

	| pair |
	pair := Array with: chain with: key.
	self isForSigning ifTrue: [
		^self subjectPublicKeyInfo algorithm isDSA
			ifTrue: [ context dsaCertificatePair: pair ]
			ifFalse: [ context rsaSigningCertificatePair: pair ] ].
	self isForKeyEstablishment ifTrue: [
		^context rsaCertificatePair: pair ].
	self error: (#CertificateNotForSSL &lt;&lt; #security &gt;&gt; 'Certificate is not suitable for SSL')</body>
</methods>

<methods>
<class-id>Security.SHA</class-id> <category>ssl</category>

<body package="SSL" selector="sslMacName">sslMacName

	^#SHA</body>

<body package="SSL" selector="sslPadding1">sslPadding1

	^RunArray new: self sslPaddingSize withAll: 16r36</body>

<body package="SSL" selector="sslPadding2">sslPadding2

	^RunArray new: self sslPaddingSize withAll: 16r5c</body>

<body package="SSL" selector="sslPaddingSize">sslPaddingSize

	^40</body>
</methods>

<methods>
<class-id>Security.ARC4</class-id> <category>ssl</category>

<body package="SSL" selector="sslCipherName">sslCipherName

	^#RC4_128</body>

<body package="SSL" selector="sslIVSize">sslIVSize

	^0</body>

<body package="SSL" selector="sslKeyMaterialSize">sslKeyMaterialSize

	^16</body>
</methods>

<methods>
<class-id>Security.MD5</class-id> <category>ssl</category>

<body package="SSL" selector="sslMacName">sslMacName

	^#MD5</body>

<body package="SSL" selector="sslPadding1">sslPadding1

	^RunArray new: self sslPaddingSize withAll: 16r36</body>

<body package="SSL" selector="sslPadding2">sslPadding2

	^RunArray new: self sslPaddingSize withAll: 16r5c</body>

<body package="SSL" selector="sslPaddingSize">sslPaddingSize

	^48</body>
</methods>

<methods>
<class-id>Security.TripleEDEOuterCBC</class-id> <category>ssl</category>

<body package="SSL" selector="sslCipherName">sslCipherName

	^('3', cipher3 sslCipherName, '_EDE_CBC') asSymbol</body>

<body package="SSL" selector="sslIVSize">sslIVSize

	^blockSize</body>

<body package="SSL" selector="sslKeyMaterialSize">sslKeyMaterialSize

	^cipher sslKeyMaterialSize * 3</body>
</methods>

<methods>
<class-id>Security.X509.Name class</class-id> <category>ssl</category>

<body package="SSL" selector="fromBytes:">fromBytes: aByteArray

	^self fromChoice: (
		(DERStream with: aByteArray)
			reset;
			unmarshalObjectType: self asn1Type )</body>
</methods>

<methods>
<class-id>Security.DSASignature class</class-id> <category>ssl</category>

<body package="SSL" selector="fromDERSequence:">fromDERSequence: aByteArray

	| rs total len r s |
	rs := aByteArray readStream.
	rs next = 16r30 ifFalse: [ self error: (#InvalidDSASigEncodingSEQ &lt;&lt; #security &gt;&gt; 'Expected SEQUENCE tag')].
	total := rs next. "SEQUENCE length &lt; 127"
	rs next = 2 ifFalse:  [ self error: (#InvalidDSASigEncodingINT &lt;&lt; #security &gt;&gt; 'Expected INTEGER tag')].
	len := rs next. "INTEGER length &lt; 127"
	r := rs next: len.
	rs next = 2 ifFalse:  [ self error: (#InvalidDSASigEncodingINT &lt;&lt; #security &gt;&gt; 'Expected INTEGER tag')].
	len := rs next. "INTEGER length &lt; 127"
	s := rs next: len.
	r := 	(	r first = 0
				ifTrue: [ r copyFrom: 2 to: r size ]
				ifFalse: [ r ]
		) asLargePositiveInteger.
	s := 	(	s first = 0
				ifTrue: [ s copyFrom: 2 to: s size ]
				ifFalse: [ s ]
		) asLargePositiveInteger.
	^self r: r s: s</body>
</methods>

<methods>
<class-id>Security.DSASignature</class-id> <category>ssl</category>

<body package="SSL" selector="asDERSequence">asDERSequence

	| total bytes ws rBytes sBytes |
	rBytes := r asBigEndianByteArray. "Gotta be big endian two's complement"
	(rBytes first bitAnd: 16r80) = 0 ifFalse: [ rBytes := #[0], rBytes ].
	sBytes := s asBigEndianByteArray. "Gotta be big endian two's complement"
	(sBytes first bitAnd: 16r80) = 0 ifFalse: [ sBytes := #[0], sBytes ].
	total := rBytes size + sBytes size.
	bytes := ByteArray new: total + 6.
	ws := bytes writeStream.
	ws 	nextPut: 16r30; "SEQUENCE tag"
		nextPut: total + 4; "SEQUENCE legth &lt; 127"
		nextPut: 2; "INTEGER tag"
		nextPut: rBytes size; "INTEGER length"
		nextPutAll:  rBytes;
		nextPut: 2; "INTEGER tag"
		nextPut: sBytes size; "INTEGER length &lt; 127"
		nextPutAll:  sBytes.
	^bytes</body>
</methods>

<methods>
<class-id>Security.CipherBlockChaining</class-id> <category>ssl</category>

<body package="SSL" selector="sslCipherName">sslCipherName

	^(cipher sslCipherName, '_CBC') asSymbol</body>

<body package="SSL" selector="sslIVSize">sslIVSize

	^blockSize</body>

<body package="SSL" selector="sslKeyMaterialSize">sslKeyMaterialSize

	^cipher sslKeyMaterialSize</body>
</methods>

<methods>
<class-id>Security.DSSRandom</class-id> <category>private</category>

<body package="SSL" selector="byteStream">byteStream

	^(FragmentStream onFragment: nil)
		setFragmentProvider: self message: #nextChunkOfRandomBytesFor:;
		yourself</body>

<body package="SSL" selector="nextChunkOfRandomBytesFor:">nextChunkOfRandomBytesFor: aFragmentStream
"This is used for secure random byte sequence generation. The method is written so that it is suitable as a fragment providing message for a fragment stream"

	^self next
		changeClassTo: ByteArray;
		yourself</body>
</methods>

<methods>
<class-id>Security.DES</class-id> <category>ssl</category>

<body package="SSL" selector="sslCipherName">sslCipherName

	^#DES</body>

<body package="SSL" selector="sslKeyMaterialSize">sslKeyMaterialSize

	^8</body>
</methods>

<do-it>"Imported Classes:"</do-it>

<do-it>self error: 'Attempting to file-in parcel imports.  Choose terminate or close'</do-it>

<class>
<name>Object</name>
<environment>Core</environment>
<super></super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Objects</category>
<attributes>
<package>Kernel-Objects</package>
</attributes>
</class>

<class>
<name>EventManager</name>
<environment>Core</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>handlers </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>System-Dependency Events</category>
<attributes>
<package>System-Dependency Events</package>
</attributes>
</class>

<class>
<name>DSASignature</name>
<environment>Security</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>r s </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>DSA</package>
</attributes>
</class>

<class>
<name>DES</name>
<environment>Security</environment>
<super>Security.BlockCipher</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>ignoreParity checkForWeakKey keySchedule encryptInPlace helperU helperT helper registerR registerU registerT registerL spRegisterTransformation skbTransformation spRegisterTransformation1 spRegisterTransformation2 spRegisterTransformation2ScratchRegister spRegisterTransformation3 spRegisterTransformation4 spRegisterTransformation5 spRegisterTransformation6 spRegisterTransformation7 spRegisterTransformation8 skbRegisterTransformation alternateShiftSequence reg arrayClass byteArrayClass largePositiveIntegerClass largePositiveScratchIntR largePositiveScratchIntU </inst-vars>
<class-inst-vars>registerClass desHelperClass arrayClass byteArrayClass largePositiveIntegerClass spRegisterTransformation skbTransformation skbRegisterTransformation alternateShiftSequence </class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>DES</package>
</attributes>
</class>

<class>
<name>Stream</name>
<environment>Core</environment>
<super>Core.Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports>
			private IOConstants.*
			</imports>
<category>Collections-Streams</category>
<attributes>
<package>Collections-Streams</package>
</attributes>
</class>

<class>
<name>ARC4</name>
<environment>Security</environment>
<super>Security.StreamCipher</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>sBox i j </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>ARC4</package>
</attributes>
</class>

<class>
<name>Certificate</name>
<environment>Security.X509</environment>
<super>Security.X509.X509Object</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>encoding tbsCertificate signatureAlgorithm signatureValue signature </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Certificates</category>
<attributes>
<package>X509</package>
</attributes>
</class>

<class>
<name>Error</name>
<environment>Core</environment>
<super>Core.Exception</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Kernel-Exception Handling</category>
<attributes>
<package>Kernel-Exception Handling</package>
</attributes>
</class>

<class>
<name>SHA</name>
<environment>Security</environment>
<super>Security.SHAHash</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>t k </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Hashes</category>
<attributes>
<package>SHA</package>
</attributes>
</class>

<class>
<name>CipherBlockChaining</name>
<environment>Security</environment>
<super>Security.BlockCipherMode</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>iv ivBackup </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>CiphersBase</package>
</attributes>
</class>

<class>
<name>MD5</name>
<environment>Security</environment>
<super>Security.Hash</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>a b c d aa bb cc dd f ff m </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Hashes</category>
<attributes>
<package>MD5</package>
</attributes>
</class>

<class>
<name>TripleEDEOuterCBC</name>
<environment>Security</environment>
<super>Security.TripleEDEInnerCBC</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>iv ivBackup block </inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>CiphersBase</package>
</attributes>
</class>

<class>
<name>DSSRandom</name>
<environment>Security</environment>
<super>Core.Random</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars>q seedMask sha auxInput mutex </inst-vars>
<class-inst-vars>default seedWarning </class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>CiphersBase</package>
</attributes>
</class>

<class>
<name>InternalEncodedStreamConstructor</name>
<environment>Core</environment>
<super>Core.EncodedStreamConstructor</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Collections-Streams</category>
<attributes>
<package>Collections-Streams</package>
</attributes>
</class>

<class>
<name>BlockPadding</name>
<environment>Security</environment>
<super>Security.BlockCipherPadding</super>
<private>false</private>
<indexed-type>none</indexed-type>
<inst-vars></inst-vars>
<class-inst-vars></class-inst-vars>
<imports></imports>
<category>Security-Ciphers</category>
<attributes>
<package>CiphersBase</package>
</attributes>
</class>

</st-source>
