Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose the peer certificates in the connection state #162

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions client-state-machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mint
import (
"bytes"
"crypto"
"crypto/x509"
"hash"
"time"
)
Expand Down Expand Up @@ -821,6 +822,10 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
} else {
logf(logTypeHandshake, "[ClientStateWaitCV] WARNING: No verification of server certificate")
}
serverCertChain := make([]*x509.Certificate, len(state.serverCertificate.CertificateList))
for i, certEntry := range state.serverCertificate.CertificateList {
serverCertChain[i] = certEntry.CertData
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the certificate authenticator do path construction?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand your point. Certificate verification is broken anyway (#161).


state.handshakeHash.Write(hm.Marshal())

Expand All @@ -831,6 +836,7 @@ func (state ClientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
cryptoParams: state.cryptoParams,
handshakeHash: state.handshakeHash,
certificates: state.certificates,
serverCertificateChain: serverCertChain,
serverCertificateRequest: state.serverCertificateRequest,
masterSecret: state.masterSecret,
clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret,
Expand All @@ -846,6 +852,7 @@ type ClientStateWaitFinished struct {
handshakeHash hash.Hash

certificates []*Certificate
serverCertificateChain []*x509.Certificate
serverCertificateRequest *CertificateRequestBody

masterSecret []byte
Expand Down Expand Up @@ -1025,14 +1032,15 @@ func (state ClientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS

logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{
Params: state.Params,
hsCtx: state.hsCtx,
isClient: true,
cryptoParams: state.cryptoParams,
resumptionSecret: resumptionSecret,
clientTrafficSecret: clientTrafficSecret,
serverTrafficSecret: serverTrafficSecret,
exporterSecret: exporterSecret,
Params: state.Params,
hsCtx: state.hsCtx,
isClient: true,
cryptoParams: state.cryptoParams,
resumptionSecret: resumptionSecret,
clientTrafficSecret: clientTrafficSecret,
serverTrafficSecret: serverTrafficSecret,
exporterSecret: exporterSecret,
PeerCertificateChain: state.serverCertificateChain,
}
return nextState, toSend, AlertNoAlert
}
3 changes: 2 additions & 1 deletion conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ var (
type ConnectionState struct {
HandshakeState State
CipherSuite CipherSuiteParams // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
PeerCertificates []*x509.Certificate // certificate chain presented by remote peer TODO([email protected]): implement
PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
NextProto string // Selected ALPN proto
}

Expand Down Expand Up @@ -875,6 +875,7 @@ func (c *Conn) State() ConnectionState {
if c.handshakeComplete {
state.CipherSuite = cipherSuiteMap[c.state.Params.CipherSuite]
state.NextProto = c.state.Params.NextProto
state.PeerCertificates = c.state.PeerCertificateChain
}

return state
Expand Down
143 changes: 71 additions & 72 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package mint

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"fmt"
"io"
Expand Down Expand Up @@ -109,75 +111,39 @@ func newBufferedConn(p net.Conn) *bufferedConn {
}

var (
serverKey, clientKey *rsa.PrivateKey
serverCert, clientCert *x509.Certificate
certificates, clientCertificates []*Certificate

psk PreSharedKey
psks *PSKMapCache

basicConfig, dtlsConfig, nbConfig, hrrConfig, alpnConfig, clientAuthConfigServer, clientAuthConfigClient, pskConfig, pskECDHEConfig, pskDHEConfig, resumptionConfig, ffdhConfig, x25519Config *Config
)

const (
serverName = "example.com"
clientName = "example.org"
)

// Certificate generated by Go
// * CN: "example.com"
// * SANs: "example.com", "www.example.com"
// * Random 2048-bit public key
// * Self-signed
serverCertHex = "308202f7308201dfa00302010202012a300d06092a864886f70d01010b05003016311430" +
"120603550403130b6578616d706c652e636f6d301e170d3135303130313030303030305a" +
"170d3235303130313030303030305a3016311430120603550403130b6578616d706c652e" +
"636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100" +
"a558ff3c12b8c4906b7f638878c71963ac95548c5d36975bc575de8775a141408c449c3e" +
"7fe7eddf93329dd894ecb2705b7f79caa06f1477b7bd2d3ff32f43076dd32a7f9f97ed4d" +
"4593db3f28adbea7794c14d8d206832652e93959e2b8d2b4781fadcf55c852641482f7fc" +
"6b9e7e751442a0818c21c9cacc28e7594606ff692392510df57ce26d9c0d052f84e236b9" +
"9e3f81daa98c554607432e3bb26a5fe3fa2b5fc5e5c1fcb1d76050328b92edc80238773d" +
"16547ccc24c0784933d86b3f8d0ee33d90a1b47ecbfbaad12e77155f1b4e84b3e5c4d565" +
"1717832fcbf82886eb6f925435b4ca9f87ec207b4338f03a846fbf0f68ea0e674bf50a21" +
"d9165b690203010001a350304e300e0603551d0f0101ff04040302028430130603551d25" +
"040c300a06082b0601050507030130270603551d110420301e820b6578616d706c652e63" +
"6f6d820f7777772e6578616d706c652e636f6d300d06092a864886f70d01010b05000382" +
"01010024ed08531171df6256ed5668b962ca3740e61c20d014b3aae8ac436b200ee89b50" +
"dc5e5a74859fdf1d0f1136ad16d5fe018dac83d0e4dcfd1b5951e1502e23b7b740621b10" +
"b3376f8b3bc5494c25917b4103d88670390e33c2b089e66326316e4bbd75fd6e5dced78f" +
"79caf97d83b981950ed10449f61d826af4a6eb70e291fccdaa76145f7ba085d27698197f" +
"60e944646640ea18d5439955d91a80d4dfb1e4c12f539da9423a33f479ee19a0fa9c5339" +
"1e0d164633bea4346dc0c8081172d67ee7bca4bd5463cc147d8c062ebb31be6e9c39518c" +
"37f5607a2d6f36114800f6c6f509893fa352a468b30ad874ae56db769f1786567e9c96c1" +
"6b4a4b2a25dda3"
serverCertDER = unhex(serverCertHex)
serverCert, _ = x509.ParseCertificate(serverCertDER)

// The corresponding private key
serverKeyHex = "308204a40201000282010100a558ff3c12b8c4906b7f638878c71963ac95548c5d36975b" +
"c575de8775a141408c449c3e7fe7eddf93329dd894ecb2705b7f79caa06f1477b7bd2d3f" +
"f32f43076dd32a7f9f97ed4d4593db3f28adbea7794c14d8d206832652e93959e2b8d2b4" +
"781fadcf55c852641482f7fc6b9e7e751442a0818c21c9cacc28e7594606ff692392510d" +
"f57ce26d9c0d052f84e236b99e3f81daa98c554607432e3bb26a5fe3fa2b5fc5e5c1fcb1" +
"d76050328b92edc80238773d16547ccc24c0784933d86b3f8d0ee33d90a1b47ecbfbaad1" +
"2e77155f1b4e84b3e5c4d5651717832fcbf82886eb6f925435b4ca9f87ec207b4338f03a" +
"846fbf0f68ea0e674bf50a21d9165b6902030100010282010074f08262ec22bcf21ef4d3" +
"621b79445d981b6cd670be4141e85f3a68b72abac979eab44e078bf25222fab3640fbf6f" +
"5bc37a5e9a8de8c1a301d1cb84e4ead20f18ff35995937cbded08c878d1da9f3a2e2488a" +
"9de5bc3159135e5aef5547bdcd60ff969f825dd0d77322455cc2882f8b822eb4f1aa37e3" +
"4d88228dac37b88f3d9b671ef6b05e2f47b562265e0d09fefb01c190c7fb4b3682231cd8" +
"564c59b6cc788ff742fb040562110b1f849f1535164503b0a402399e2c6cf1c0847dd50a" +
"a917b62fc3215e4eb43d7d07fa9731a51e01f0f7b694dd002b48c0bad04b9ff34e576393" +
"c0a213a12dda4bf43a7dd4ee0563c5e0de2025eb76e049cd771c96330102818100c590bd" +
"8f226cec50c818afb3ebe7ceeacabb107ac73ac159b1eca1a194ea550a0609c432a183e2" +
"fee62dafdc0201426f90cb46f9b2fc7a9bcc2365b58177529cf78c209eb6a3afd1896466" +
"63e8462729e8bf902dc1c42c7d46c1c0c99c632f0560418604b4260a1ed8d165375c674c" +
"806c2a8e202d0b7c5a8b8717309106fb3102818100d640cae7b6adea649a8c11863a3ba8" +
"098025a972d130aecaa4db08154fd0feb8af79bf7009c1ea2a790752464e923b53b41ff4" +
"3ff84e6ddb94bfc5b157e6a21e1fefe11cc082e7e8b31d07eab5e13d7a84cdeeba24d283" +
"699a8fa5138e753e88856a033ab2153c1a8200caac28377a1d09d6318ac2e946cef879a0" +
"5acbd8e5b902818100bfe142ea189257b66190f05d3bba8951aa92a27fccadf90a076f7e" +
"cff354e040fafa534ea565f57a81ce4fa5cb60b3c8ad8570aaa5b6e7d217232dee6a0e9c" +
"f30cce510434f8a79347f0762d84735628330092a48e33dccdd381ec9f233f8574a03723" +
"55c02dcdd885d6618ab23935a8e8e52fe27a3d548a90472533ab376f910281805253fd64" +
"02875bbd22c1d5ee0d2c654a994a5f8d7622cdd7a27763e8c48ddb835e325b44930b478e" +
"e088d6ad9b7d877c87878bd494f696323d3b5f9ce0d907cca99b049686c706941d577776" +
"524365db5172cc5c0cd0339cfdbe5ac164095b691c52fb40afb3872fec6a9f767dd1ab83" +
"c306e26c9eaf02fd7eef4595fe24af4902818100b5a2294d7567283f3f4bf54be7b98785" +
"fc564f24ff2d67215ecdc7955cbf05260f48c9608a59a8ebfbedc62b4d110c1704ade704" +
"cb27a591f69752d1d6ebe21291aec29b301efe47eced0187125f741ce52b3826beac3778" +
"f3560448e91644fd52460f8c3afa1596c01e6cd2c37120d8122c09edf326988b48d98c27" +
"f788eb83"
serverKeyDER = unhex(serverKeyHex)
serverKey, _ = x509.ParsePKCS1PrivateKey(serverKeyDER)
func init() {
var err error
serverKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
serverCert, err = newSelfSigned(serverName, RSA_PKCS1_SHA256, serverKey)
if err != nil {
panic(err)
}
clientKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
clientCert, err = newSelfSigned(clientName, RSA_PKCS1_SHA256, clientKey)
if err != nil {
panic(err)
}

psk = PreSharedKey{
CipherSuite: TLS_AES_128_GCM_SHA256,
Expand All @@ -191,6 +157,12 @@ var (
PrivateKey: serverKey,
},
}
clientCertificates = []*Certificate{
{
Chain: []*x509.Certificate{clientCert},
PrivateKey: clientKey,
},
}
psks = &PSKMapCache{
serverName: psk,
"00010203": psk,
Expand Down Expand Up @@ -225,11 +197,14 @@ var (
NextProtos: []string{"http/1.1", "h2"},
}

clientAuthConfig = &Config{
ServerName: serverName,
clientAuthConfigServer = &Config{
RequireClientAuth: true,
Certificates: certificates,
}
clientAuthConfigClient = &Config{
ServerName: serverName,
Certificates: clientCertificates,
}

pskConfig = &Config{
ServerName: serverName,
Expand Down Expand Up @@ -272,7 +247,7 @@ var (
CipherSuites: []CipherSuite{TLS_AES_128_GCM_SHA256},
Groups: []NamedGroup{X25519},
}
)
}

func assertKeySetEquals(t *testing.T, k1, k2 keySet) {
t.Helper()
Expand Down Expand Up @@ -342,8 +317,8 @@ func TestBasicFlows(t *testing.T) {
func TestClientAuth(t *testing.T) {
cConn, sConn := pipe()

client := Client(cConn, clientAuthConfig)
server := Server(sConn, clientAuthConfig)
client := Client(cConn, clientAuthConfigClient)
server := Server(sConn, clientAuthConfigServer)

var clientAlert, serverAlert Alert

Expand Down Expand Up @@ -825,6 +800,30 @@ func TestExternalExtensions(t *testing.T) {
})
}

func TestConnectionState(t *testing.T) {
cConn, sConn := pipe()
client := Client(cConn, clientAuthConfigClient)
server := Server(sConn, clientAuthConfigServer)

done := make(chan bool)
go func(t *testing.T) {
serverAlert := server.Handshake()
assertEquals(t, serverAlert, AlertNoAlert)
done <- true
}(t)

clientAlert := client.Handshake()
assertEquals(t, clientAlert, AlertNoAlert)
<-done

clientConnectionState := client.State()
assertEquals(t, clientConnectionState.CipherSuite.Suite, clientAuthConfigClient.CipherSuites[0])
assertDeepEquals(t, clientConnectionState.PeerCertificates, []*x509.Certificate{serverCert})
serverConnectionState := server.State()
assertEquals(t, serverConnectionState.CipherSuite.Suite, clientAuthConfigServer.CipherSuites[0])
assertDeepEquals(t, serverConnectionState.PeerCertificates, []*x509.Certificate{clientCert})
}

func TestDTLS(t *testing.T) {
cConn, sConn := pipe()

Expand Down
25 changes: 17 additions & 8 deletions server-state-machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mint

import (
"bytes"
"crypto/x509"
"fmt"
"hash"
"reflect"
Expand Down Expand Up @@ -994,6 +995,10 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
} else {
logf(logTypeHandshake, "[ServerStateWaitCV] WARNING: No verification of client certificate")
}
clientCertChain := make([]*x509.Certificate, len(state.clientCertificate.CertificateList))
for i, certEntry := range state.clientCertificate.CertificateList {
clientCertChain[i] = certEntry.CertData
}

// If it passes, record the certificateVerify in the transcript hash
state.handshakeHash.Write(hm.Marshal())
Expand All @@ -1005,6 +1010,7 @@ func (state ServerStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState,
cryptoParams: state.cryptoParams,
masterSecret: state.masterSecret,
clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret,
clientCertificateChain: clientCertChain,
handshakeHash: state.handshakeHash,
clientTrafficSecret: state.clientTrafficSecret,
serverTrafficSecret: state.serverTrafficSecret,
Expand All @@ -1021,6 +1027,8 @@ type ServerStateWaitFinished struct {
masterSecret []byte
clientHandshakeTrafficSecret []byte

clientCertificateChain []*x509.Certificate

handshakeHash hash.Hash
clientTrafficSecret []byte
serverTrafficSecret []byte
Expand Down Expand Up @@ -1074,14 +1082,15 @@ func (state ServerStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS

logf(logTypeHandshake, "[ServerStateWaitFinished] -> [StateConnected]")
nextState := StateConnected{
Params: state.Params,
hsCtx: state.hsCtx,
isClient: false,
cryptoParams: state.cryptoParams,
resumptionSecret: resumptionSecret,
clientTrafficSecret: state.clientTrafficSecret,
serverTrafficSecret: state.serverTrafficSecret,
exporterSecret: state.exporterSecret,
Params: state.Params,
hsCtx: state.hsCtx,
isClient: false,
cryptoParams: state.cryptoParams,
resumptionSecret: resumptionSecret,
clientTrafficSecret: state.clientTrafficSecret,
serverTrafficSecret: state.serverTrafficSecret,
exporterSecret: state.exporterSecret,
PeerCertificateChain: state.clientCertificateChain,
}
toSend := []HandshakeAction{
RekeyIn{epoch: EpochApplicationData, KeySet: clientTrafficKeys},
Expand Down
3 changes: 3 additions & 0 deletions state-machine.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mint

import (
"crypto/x509"
"time"
)

Expand Down Expand Up @@ -114,6 +115,8 @@ type StateConnected struct {
clientTrafficSecret []byte
serverTrafficSecret []byte
exporterSecret []byte

PeerCertificateChain []*x509.Certificate
}

var _ HandshakeState = &StateConnected{}
Expand Down