forked from msgboxio/ike
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauthenticator_cert.go
97 lines (90 loc) · 3.1 KB
/
authenticator_cert.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package ike
import (
"bytes"
"crypto/x509"
"encoding/hex"
"fmt"
"github.com/go-kit/kit/log"
"github.com/msgboxio/ike/protocol"
"github.com/pkg/errors"
)
// CertAuthenticator is an Authenticator
type CertAuthenticator struct {
tkm *Tkm
forInitiator bool
identity Identity
rfc7427Signatures bool
}
// this is an Authenticator
var _ Authenticator = (*CertAuthenticator)(nil)
func (o *CertAuthenticator) Identity() Identity {
return o.identity
}
func (o *CertAuthenticator) Sign(initB []byte, idP *protocol.IdPayload, logger log.Logger) ([]byte, error) {
certID, ok := o.identity.(*CertIdentity)
if !ok {
// should never happen
panic("Logic Error")
}
// certificate is not required to sign
// it is transferred to peer, and hopefully signature algos are compatible
if certID.Certificate == nil {
return nil, errors.Errorf("missing certificate")
}
if certID.PrivateKey == nil {
return nil, errors.Errorf("missing private key")
}
cert := FormatCert(certID.Certificate)
logger.Log("AUTH", fmt.Sprintf("OUR_CERT[%s]", cert.String()))
signed := o.tkm.SignB(initB, idP.Encode(), o.forInitiator)
// try and use the configured method
authMethod := certID.AuthMethod()
if !o.rfc7427Signatures {
authMethod = protocol.AUTH_RSA_DIGITAL_SIGNATURE
}
return CreateSignature(certID.Certificate.SignatureAlgorithm, authMethod, signed, certID.PrivateKey, logger)
}
// Verify using one of:
// AUTH_RSA_DIGITAL_SIGNATURE with certificates
// RFC 7427 - Signature Authentication in IKEv2
// tkm.Auth always uses the hash negotiated with prf
// TODO: implement raw AUTH_RSA_DIGITAL_SIGNATURE & AUTH_DSS_DIGITAL_SIGNATURE
// TODO: implement ECDSA from RFC4754
func (o *CertAuthenticator) Verify(initB []byte, idP *protocol.IdPayload, authMethod protocol.AuthMethod, authData []byte, inbandData interface{}, logger log.Logger) error {
chain, ok := inbandData.([]*x509.Certificate)
if !ok {
// should never happen
panic("logic error")
}
if len(chain) == 0 {
return errors.New("missing certificates")
}
// TODO -
cert := FormatCert(chain[0])
logger.Log("AUTH", fmt.Sprintf("PEER_CERT[%s]", cert.String()))
// ensure key used to compute a digital signature belongs to the name in the ID payload
if bytes.Compare(idP.Data, chain[0].RawSubject) != 0 {
return errors.Errorf("Incorrect id in certificate: %s", hex.Dump(chain[0].RawSubject))
}
// find identity
certID, ok := o.identity.(*CertIdentity)
if !ok {
// should never happen
panic("logic error")
}
// Verify validity of certificate
opts := x509.VerifyOptions{
Roots: certID.Roots,
}
if _, err := chain[0].Verify(opts); err != nil {
return errors.Wrap(err, "Unable to verify certificate")
}
// ensure that certificate is for authorized ID: check in subject & altname
// TODO - is this reasonable?
if !MatchNameFromCert(&cert, certID.Name) {
return errors.Errorf("Certificate is not Authorized for Name: %s", certID.Name)
}
signed := o.tkm.SignB(initB, idP.Encode(), !o.forInitiator)
// try and use the configured method // TODO - check for inconsistency ?
return VerifySignature(authMethod, signed, authData, chain[0], logger)
}