0. Variants
Defined structures may have variants based on some knowledge that is
available within the environment. The selector must be an enumerated
type that defines the possible variants the structure defines. There
must be a case arm for every element of the enumeration declared in
the select. The body of the variant structure may be given a label
for reference. The mechanism by which the variant is selected at
runtime is not prescribed by the presentation language.
struct {
T1 f1;
T2 f2;
....
Tn fn;
select (E) {
case e1: Te1;
case e2: Te2;
....
case en: Ten;
} [[fv]];
} [[Tv]];
For example:
enum { apple, orange } VariantTag;
struct {
uint16 number;
opaque string<0..10>; /* variable length */
} V1;
struct {
uint32 number;
opaque string[10]; /* fixed length */
} V2;
struct {
select (VariantTag) { /* value of selector is implicit */
case apple: V1; /* VariantBody, tag = apple */
case orange: V2; /* VariantBody, tag = orange */
} variant_body; /* optional label on variant */
} VariantRecord;
Variant structures may be qualified (narrowed) by specifying a value
for the selector prior to the type. For example, an
orange VariantRecord
is a narrowed type of a VariantRecord containing a variant_body of
type V2.
1. RECORD LAYER PROTOCOL:
struct {
uint8 major, minor;
} ProtocolVersion;
enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
1.1 HANDSHAKE FLOW:
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
1.2 HANDSHAKE PROTOCAL:
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_hello_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20), (255)
} HandshakeType;
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
1.2.1 CLIENT_HELLO:
struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;
opaque SessionID<0..32>;
uint8 CipherSuite[2]; /* Cryptographic suite selector [LENGTH+LIST]*/
enum { null(0), (255) } CompressionMethod;
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-1>;
CompressionMethod compression_methods<1..2^8-1>;
} ClientHello;
关于客户端的cipher_suites,重要:
cipher_suites
This is a list of the cryptographic options supported by the
client, with the client's first preference first. If the
session_id field is not empty (implying a session resumption
request) this vector MUST include at least the cipher_suite from
that session. Values are defined in Appendix A.5.
Each CipherSuite defines a key exchange algorithm, a bulk encryption
algorithm (including secret key length), and a MAC algorithm.
1.2.2 SERVER_HELLO:
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
} ServerHello;
关于session_id的说明, 涉及复用:
session_id
This is the identity of the session corresponding to this
connection. If the ClientHello.session_id was non-empty, the
server will look in its session cache for a match. If a match is
found and the server is willing to establish the new connection
using the specified session state, the server will respond with
the same value as was supplied by the client. This indicates a
resumed session and dictates that the parties must proceed
directly to the finished messages. Otherwise this field will
contain a different value identifying the new session. The server
may return an empty session_id to indicate that the session will
not be cached and therefore cannot be resumed. If a session is
resumed, it must be resumed using the same cipher suite it was
originally negotiated with.
cipher_suite的说明:
cipher_suite
The single cipher suite selected by the server from the list in
ClientHello.cipher_suites. For resumed sessions, this field is
the value from the state of the session being resumed.
1.2.3 Server Certificate:
消息类型(需要查看x509v3的rfc: RFC3280):
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
关于服务端证书的一些说明:
When this message will be sent:
The server MUST send a certificate whenever the agreed-upon key
exchange method is not an anonymous one. This message will always
immediately follow the server hello message.
Meaning of this message:
The certificate type MUST be appropriate for the selected cipher
suite's key exchange algorithm, and is generally an X.509v3
certificate. It MUST contain a key that matches the key exchange
method, as follows. Unless otherwise specified, the signing
algorithm for the certificate MUST be the same as the algorithm
for the certificate key. Unless otherwise specified, the public
key MAY be of any length.
密钥交换算法的证书密钥类型:
Key Exchange Algorithm Certificate Key Type
RSA RSA public key; the certificate MUST
allow the key to be used for encryption.
DHE_DSS DSS public key.
DHE_RSA RSA public key that can be used for
signing.
DH_DSS Diffie-Hellman key. The algorithm used
to sign the certificate MUST be DSS.
DH_RSA Diffie-Hellman key. The algorithm used
to sign the certificate MUST be RSA.
All certificate profiles and key and cryptographic formats are
defined by the IETF PKIX working group [PKIX]. When a key usage
extension is present, the digitalSignature bit MUST be set for the
key to be eligible for signing, as described above, and the
keyEncipherment bit MUST be present to allow encryption, as described
above. The keyAgreement bit must be set on Diffie-Hellman
certificates.
关于证书链的说明:
Structure of this message:
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
certificate_list
This is a sequence (chain) of X.509v3 certificates. The sender's
certificate must come first in the list. Each following
certificate must directly certify the one preceding it. Because
certificate validation requires that root keys be distributed
independently, the self-signed certificate that specifies the root
certificate authority may optionally be omitted from the chain,
under the assumption that the remote end must already possess it
in order to validate it in any case.
1.2.4 Server Key Exchange Message:
这个需要看下DH交换和RSA交换的RFC,以便理解发送的参数:
Structure of this message:
enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
struct {
opaque rsa_modulus<1..2^16-1>;
opaque rsa_exponent<1..2^16-1>;
} ServerRSAParams;
rsa_modulus
The modulus of the server's temporary RSA key.
rsa_exponent
The public exponent of the server's temporary RSA key.
struct {
opaque dh_p<1..2^16-1>;
opaque dh_g<1..2^16-1>;
opaque dh_Ys<1..2^16-1>;
} ServerDHParams; /* Ephemeral DH parameters */
dh_p
The prime modulus used for the Diffie-Hellman operation.
dh_g
The generator used for the Diffie-Hellman operation.
dh_Ys
The server's Diffie-Hellman public value (g^X mod p).
struct {
select (KeyExchangeAlgorithm) {
case diffie_hellman:
ServerDHParams params;
Signature signed_params;
case rsa:
ServerRSAParams params;
Signature signed_params;
};
} ServerKeyExchange;
struct {
select (KeyExchangeAlgorithm) {
case diffie_hellman:
ServerDHParams params;
case rsa:
ServerRSAParams params;
};
} ServerParams;
params
The server's key exchange parameters.
signed_params
For non-anonymous key exchanges, a hash of the corresponding
params value, with the signature appropriate to that hash
applied.
md5_hash
MD5(ClientHello.random + ServerHello.random + ServerParams);
sha_hash
SHA(ClientHello.random + ServerHello.random + ServerParams);
enum { anonymous, rsa, dsa } SignatureAlgorithm;
struct {
select (SignatureAlgorithm) {
case anonymous: struct { };
case rsa:
digitally-signed struct {
opaque md5_hash[16];
opaque sha_hash[20];
};
case dsa:
digitally-signed struct {
opaque sha_hash[20];
};
};
};
} Signature;
1.2.5 Certificate request:
When this message will be sent:
A non-anonymous server can optionally request a certificate from
the client, if it is appropriate for the selected cipher suite.
This message, if sent, will immediately follow the Server Key
Exchange message (if it is sent; otherwise, the Server Certificate
message).
Structure of this message:
enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
fortezza_dms_RESERVED(20), (255)
} ClientCertificateType;
opaque DistinguishedName<1..2^16-1>;
struct {
ClientCertificateType certificate_types<1..2^8-1>;
DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
certificate_types
This field is a list of the types of certificates requested,
sorted in order of the server's preference.
Values from 0 (zero) through 63 decimal (0x3F) inclusive are
reserved for IETF Standards Track protocols.
certificate_authorities
A list of the distinguished names of acceptable certificate
authorities. These distinguished names may specify a desired
distinguished name for a root CA or for a subordinate CA; thus,
this message can be used to describe both known roots and a
desired authorization space. If the certificate_authorities
list is empty then the client MAY send any certificate of the
appropriate ClientCertificateType, unless there is some
external arrangement to the contrary.
Note: It is a fatal handshake_failure alert for an anonymous server
to request client authentication.
1.2.6 Server Hello Done
服务端发送这个消息表示server hello阶段的结束. 服务端发送此消息后将会
等待客户端的回应.此消息意味着服务端支持key exchange的消息发送完毕,
客户端可以继续它自己的key exchange的阶段.收到服务端的这个消息,客户端
SHOULD确认服务端提供了一个有效的证书(如果需要)并且检查server hello的
参数是可接受的.
Structure of this message:
struct { } ServerHelloDone;
1.2.7 Client certificate
When this message will be sent:
这是客户端收到server_hello_done之后发送的第一个消息.客户端发送此消
息只有服务端发送了certificate_request消息时. 如果无可用证书,客户端
SHOULD发送一个不包含证书的证书消息.也就是length为0的certificate_list
结构.如果服务端对于客户端验证时require的,那将会导致一个fatal
handshake failure alert.
Note: When using a static Diffie-Hellman based key exchange method
(DH_DSS or DH_RSA), if client authentication is requested, the
Diffie-Hellman group and generator encoded in the client's
certificate MUST match the server specified Diffie-Hellman
parameters if the client's parameters are to be used for the key
exchange.
1.2.8 Client Key Exchange Message:
When this message will be sent:
由客户端发送,且MUST紧跟client certificate message(如果发送),否则
就作为收到server hello done之后的第一个消息.
Meaning of this message:
With this message, the premaster secret is set, either though
direct transmission of the RSA-encrypted secret or by the
transmission of Diffie-Hellman parameters that will allow each
side to agree upon the same premaster secret. When the key
exchange method is DH_RSA or DH_DSS, client certification has been
requested, and the client was able to respond with a certificate
that contained a Diffie-Hellman public key whose parameters (group
and generator) matched those specified by the server in its
certificate, this message MUST not contain any data.
Structure of this message:
The choice of messages depends on which key exchange method has
been selected. See Section 1.2.4 for the KeyExchangeAlgorithm
definition.
struct {
select (KeyExchangeAlgorithm) {
case rsa: EncryptedPreMasterSecret;
case diffie_hellman: ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;
1.2.8.1 RSA Encrypted Premaster Secret Message
Meaning of this message:
If RSA is being used for key agreement and authentication, the
client generates a 48-byte premaster secret, encrypts it using the
public key from the server's certificate or the temporary RSA key
provided in a server key exchange message, and sends the result in
an encrypted premaster secret message. This structure is a
variant of the client key exchange message and is not a message in
itself.
Structure of this message:
struct {
ProtocolVersion client_version;
opaque random[46];
} PreMasterSecret;
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.
random
46 securely-generated random bytes.
struct {
public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;
pre_master_secret
This random value is generated by the client and is used to
generate the master secret.
1.2.8.2 Client Diffie-Hellman Public Value
Meaning of this message:
This structure conveys the client's Diffie-Hellman public value
(Yc) if it was not already included in the client's certificate.
The encoding used for Yc is determined by the enumerated
PublicValueEncoding. 这个是一个变体,不是消息本身.
Structure of this message:
enum { implicit, explicit } PublicValueEncoding;
implicit
If the client certificate already contains a suitable Diffie-
Hellman key, then Yc is implicit and does not need to be sent
again. In this case, the client key exchange message will be
sent, but it MUST be empty.
explicit
Yc needs to be sent.
struct {
select (PublicValueEncoding) {
case implicit: struct { };
case explicit: opaque dh_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;
dh_Yc
The client's Diffie-Hellman public value (Yc).
1.2.9 Certificate verify
When this message will be sent:
This message is used to provide explicit verification of a client
certificate.When
sent, it MUST immediately follow the client key exchange message.
Structure of this message:
struct {
Signature signature;
} CertificateVerify;
The Signature type is defined in 1.2.4.
CertificateVerify.signature.md5_hash
MD5(handshake_messages);
CertificateVerify.signature.sha_hash
SHA(handshake_messages);
Here handshake_messages refers to all handshake messages sent or
received starting at client hello up to but not including this
message, including the type and length fields of the handshake
messages.
1.2.10 Finished(密文的,抓包看不到的)
When this message will be sent:
A finished message is always sent immediately after a change
cipher spec message to verify that the key exchange and
authentication processes were successful. It is essential that a
change cipher spec message be received between the other handshake
messages and the Finished message.(中间的change cipher spec是必要的)
Meaning of this message:
The finished message is the first protected with the just-
negotiated algorithms, keys, and secrets. Recipients of finished
messages MUST verify that the contents are correct. Once a side
has sent its Finished message and received and validated the
Finished message from its peer, it may begin to send and receive
application data over the connection.
Structure of this message:
struct {
opaque verify_data[12];
} Finished;
verify_data
PRF(master_secret, finished_label, MD5(handshake_messages) +
SHA-1(handshake_messages)) [0..11];
finished_label
For Finished messages sent by the client, the string "client
finished". For Finished messages sent by the server, the
string "server finished".
handshake_messages
All of the data from all messages in this handshake (not
including any HelloRequest messages) up to but not including
this message. This is only data visible at the handshake
layer and does not include record layer headers. This is the
concatenation of all the Handshake structures, as defined in
7.4, exchanged thus far.
2 Cryptographic Computations
为了保护连接, TLS的记录层需要一组算法,主密钥,服务端和客户端随机数的
详细说明. authentication, encryption, and MAC algorithms由服务端选择
的cipher_suite决定,并在server hello消息中指明.压缩算法在hello消息中
协商.所有上述这些都用作计算主密钥.
2.1. Computing the Master Secret
For all key exchange methods, the same algorithm is used to convert
the pre_master_secret into the master_secret. The pre_master_secret
should be deleted from memory once the master_secret has been
computed.
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
[0..47];
The master secret is always exactly 48 bytes in length. The length
of the premaster secret will vary depending on key exchange method.
2.1.1. RSA
When RSA is used for server authentication and key exchange, a 48-
byte pre_master_secret is generated by the client, encrypted under
the server's public key, and sent to the server. The server uses its
private key to decrypt the pre_master_secret. Both parties then
convert the pre_master_secret into the master_secret, as specified
above.
RSA digital signatures are performed using PKCS #1 [PKCS1] block type
1. RSA public key encryption is performed using PKCS #1 block type 2.
2.1.2. Diffie-Hellman
A conventional Diffie-Hellman computation is performed. The
negotiated key (Z) is used as the pre_master_secret, and is converted
into the master_secret, as specified above. Leading bytes of Z that
contain all zero bits are stripped before it is used as the
pre_master_secret.
Note: Diffie-Hellman parameters are specified by the server and may
be either ephemeral or contained within the server's
certificate.