Client authentication

This commit is contained in:
Henry Case 2018-03-26 16:20:25 +01:00 committed by Henry Dorsett Case
parent e62ddc004c
commit c6745f1879

124
13.go
View File

@ -792,6 +792,87 @@ func (hs *clientHandshakeState) verifyPeerCertificate(certVerify *certificateVer
return nil return nil
} }
func (hs *clientHandshakeState) getCertificate13(certReq *certificateRequestMsg13) (*Certificate, error) {
certReq12 := &certificateRequestMsg{
hasSignatureAndHash: true,
supportedSignatureAlgorithms: certReq.supportedSignatureAlgorithms,
certificateAuthorities: certReq.certificateAuthorities,
}
var rsaAvail, ecdsaAvail bool
for _, sigAlg := range certReq.supportedSignatureAlgorithms {
switch signatureFromSignatureScheme(sigAlg) {
case signaturePKCS1v15, signatureRSAPSS:
rsaAvail = true
case signatureECDSA:
ecdsaAvail = true
}
}
if rsaAvail {
certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeRSASign)
}
if ecdsaAvail {
certReq12.certificateTypes = append(certReq12.certificateTypes, certTypeECDSASign)
}
return hs.getCertificate(certReq12)
}
func (hs *clientHandshakeState) sendCertificate13(chainToSend *Certificate, certReq *certificateRequestMsg13) error {
c := hs.c
certEntries := []certificateEntry{}
for _, cert := range chainToSend.Certificate {
certEntries = append(certEntries, certificateEntry{data: cert})
}
certMsg := &certificateMsg13{certificates: certEntries}
hs.keySchedule.write(certMsg.marshal())
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
return err
}
if len(certEntries) == 0 {
// No client cert available, nothing to sign.
return nil
}
key, ok := chainToSend.PrivateKey.(crypto.Signer)
if !ok {
c.sendAlert(alertInternalError)
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
}
signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers)
if err != nil {
hs.c.sendAlert(alertHandshakeFailure)
return err
}
digest := prepareDigitallySigned(hashFunc, "TLS 1.3, client CertificateVerify", hs.keySchedule.transcriptHash.Sum(nil))
signOpts := crypto.SignerOpts(hashFunc)
if sigType == signatureRSAPSS {
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
}
signature, err := key.Sign(c.config.rand(), digest, signOpts)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
verifyMsg := &certificateVerifyMsg{
hasSignatureAndHash: true,
signatureAlgorithm: signatureAlgorithm,
signature: signature,
}
hs.keySchedule.write(verifyMsg.marshal())
if _, err := c.writeRecord(recordTypeHandshake, verifyMsg.marshal()); err != nil {
return err
}
return nil
}
func (hs *clientHandshakeState) doTLS13Handshake() error { func (hs *clientHandshakeState) doTLS13Handshake() error {
c := hs.c c := hs.c
hash := hashForSuite(hs.suite) hash := hashForSuite(hs.suite)
@ -853,7 +934,23 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
if err != nil { if err != nil {
return err return err
} }
// TODO handle optional CertificateRequest
var chainToSend *Certificate
certReq, isCertRequested := msg.(*certificateRequestMsg13)
if isCertRequested {
hs.keySchedule.write(certReq.marshal())
if chainToSend, err = hs.getCertificate13(certReq); err != nil {
c.sendAlert(alertInternalError)
return err
}
msg, err = c.readHandshake()
if err != nil {
return err
}
}
certMsg, ok := msg.(*certificateMsg13) certMsg, ok := msg.(*certificateMsg13)
if !ok { if !ok {
c.sendAlert(alertUnexpectedMessage) c.sendAlert(alertUnexpectedMessage)
@ -898,10 +995,21 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
} }
hs.keySchedule.write(serverFinished.marshal()) hs.keySchedule.write(serverFinished.marshal())
// Server has authenticated itself, change our cipher. // Server has authenticated itself. Calculate application traffic secrets.
hs.keySchedule.setSecret(nil) // derive master secret
appServerCipher, _ := hs.keySchedule.prepareCipher(secretApplicationServer)
appClientCipher, _ := hs.keySchedule.prepareCipher(secretApplicationClient)
// Change outbound handshake cipher for final step
c.out.setCipher(c.vers, clientCipher) c.out.setCipher(c.vers, clientCipher)
// TODO optionally send a client cert // Client auth requires sending a (possibly empty) Certificate followed
// by a CertificateVerify message (if there was an actual certificate).
if isCertRequested {
if err := hs.sendCertificate13(chainToSend, certReq); err != nil {
return err
}
}
// Send Finished // Send Finished
verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, clientFinishedKey) verifyData := hmacOfSum(hash, hs.keySchedule.transcriptHash, clientFinishedKey)
@ -912,16 +1020,14 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
return err return err
} }
// Calculate application traffic secrets.
hs.keySchedule.setSecret(nil) // derive master secret
// TODO store initial traffic secret key for KeyUpdate // TODO store initial traffic secret key for KeyUpdate
clientCipher, _ = hs.keySchedule.prepareCipher(secretApplicationClient)
serverCipher, _ = hs.keySchedule.prepareCipher(secretApplicationServer) // Handshake done, set application traffic secret
c.out.setCipher(c.vers, clientCipher) c.out.setCipher(c.vers, appClientCipher)
if c.hand.Len() > 0 { if c.hand.Len() > 0 {
c.sendAlert(alertUnexpectedMessage) c.sendAlert(alertUnexpectedMessage)
return errors.New("tls: unexpected data after handshake") return errors.New("tls: unexpected data after handshake")
} }
c.in.setCipher(c.vers, serverCipher) c.in.setCipher(c.vers, appServerCipher)
return nil return nil
} }