| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package dtls
- import (
- "crypto"
- "crypto/ecdsa"
- "crypto/ed25519"
- "crypto/rand"
- "crypto/rsa"
- "crypto/sha256"
- "crypto/x509"
- "encoding/asn1"
- "encoding/binary"
- "math/big"
- "time"
- "github.com/pion/dtls/v2/pkg/crypto/elliptic"
- "github.com/pion/dtls/v2/pkg/crypto/hash"
- )
- type ecdsaSignature struct {
- R, S *big.Int
- }
- func valueKeyMessage(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve) []byte {
- serverECDHParams := make([]byte, 4)
- serverECDHParams[0] = 3 // named curve
- binary.BigEndian.PutUint16(serverECDHParams[1:], uint16(namedCurve))
- serverECDHParams[3] = byte(len(publicKey))
- plaintext := []byte{}
- plaintext = append(plaintext, clientRandom...)
- plaintext = append(plaintext, serverRandom...)
- plaintext = append(plaintext, serverECDHParams...)
- plaintext = append(plaintext, publicKey...)
- return plaintext
- }
- // If the client provided a "signature_algorithms" extension, then all
- // certificates provided by the server MUST be signed by a
- // hash/signature algorithm pair that appears in that extension
- //
- // https://tools.ietf.org/html/rfc5246#section-7.4.2
- func generateKeySignature(clientRandom, serverRandom, publicKey []byte, namedCurve elliptic.Curve, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
- msg := valueKeyMessage(clientRandom, serverRandom, publicKey, namedCurve)
- switch p := privateKey.(type) {
- case ed25519.PrivateKey:
- // https://crypto.stackexchange.com/a/55483
- return p.Sign(rand.Reader, msg, crypto.Hash(0))
- case *ecdsa.PrivateKey:
- hashed := hashAlgorithm.Digest(msg)
- return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
- case *rsa.PrivateKey:
- hashed := hashAlgorithm.Digest(msg)
- return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
- }
- return nil, errKeySignatureGenerateUnimplemented
- }
- func verifyKeySignature(message, remoteKeySignature []byte, hashAlgorithm hash.Algorithm, rawCertificates [][]byte) error { //nolint:dupl
- if len(rawCertificates) == 0 {
- return errLengthMismatch
- }
- certificate, err := x509.ParseCertificate(rawCertificates[0])
- if err != nil {
- return err
- }
- switch p := certificate.PublicKey.(type) {
- case ed25519.PublicKey:
- if ok := ed25519.Verify(p, message, remoteKeySignature); !ok {
- return errKeySignatureMismatch
- }
- return nil
- case *ecdsa.PublicKey:
- ecdsaSig := &ecdsaSignature{}
- if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
- return err
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return errInvalidECDSASignature
- }
- hashed := hashAlgorithm.Digest(message)
- if !ecdsa.Verify(p, hashed, ecdsaSig.R, ecdsaSig.S) {
- return errKeySignatureMismatch
- }
- return nil
- case *rsa.PublicKey:
- switch certificate.SignatureAlgorithm {
- case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
- hashed := hashAlgorithm.Digest(message)
- return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hashed, remoteKeySignature)
- default:
- return errKeySignatureVerifyUnimplemented
- }
- }
- return errKeySignatureVerifyUnimplemented
- }
- // If the server has sent a CertificateRequest message, the client MUST send the Certificate
- // message. The ClientKeyExchange message is now sent, and the content
- // of that message will depend on the public key algorithm selected
- // between the ClientHello and the ServerHello. If the client has sent
- // a certificate with signing ability, a digitally-signed
- // CertificateVerify message is sent to explicitly verify possession of
- // the private key in the certificate.
- // https://tools.ietf.org/html/rfc5246#section-7.3
- func generateCertificateVerify(handshakeBodies []byte, privateKey crypto.PrivateKey, hashAlgorithm hash.Algorithm) ([]byte, error) {
- h := sha256.New()
- if _, err := h.Write(handshakeBodies); err != nil {
- return nil, err
- }
- hashed := h.Sum(nil)
- switch p := privateKey.(type) {
- case ed25519.PrivateKey:
- // https://crypto.stackexchange.com/a/55483
- return p.Sign(rand.Reader, hashed, crypto.Hash(0))
- case *ecdsa.PrivateKey:
- return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
- case *rsa.PrivateKey:
- return p.Sign(rand.Reader, hashed, hashAlgorithm.CryptoHash())
- }
- return nil, errInvalidSignatureAlgorithm
- }
- func verifyCertificateVerify(handshakeBodies []byte, hashAlgorithm hash.Algorithm, remoteKeySignature []byte, rawCertificates [][]byte) error { //nolint:dupl
- if len(rawCertificates) == 0 {
- return errLengthMismatch
- }
- certificate, err := x509.ParseCertificate(rawCertificates[0])
- if err != nil {
- return err
- }
- switch p := certificate.PublicKey.(type) {
- case ed25519.PublicKey:
- if ok := ed25519.Verify(p, handshakeBodies, remoteKeySignature); !ok {
- return errKeySignatureMismatch
- }
- return nil
- case *ecdsa.PublicKey:
- ecdsaSig := &ecdsaSignature{}
- if _, err := asn1.Unmarshal(remoteKeySignature, ecdsaSig); err != nil {
- return err
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return errInvalidECDSASignature
- }
- hash := hashAlgorithm.Digest(handshakeBodies)
- if !ecdsa.Verify(p, hash, ecdsaSig.R, ecdsaSig.S) {
- return errKeySignatureMismatch
- }
- return nil
- case *rsa.PublicKey:
- switch certificate.SignatureAlgorithm {
- case x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA:
- hash := hashAlgorithm.Digest(handshakeBodies)
- return rsa.VerifyPKCS1v15(p, hashAlgorithm.CryptoHash(), hash, remoteKeySignature)
- default:
- return errKeySignatureVerifyUnimplemented
- }
- }
- return errKeySignatureVerifyUnimplemented
- }
- func loadCerts(rawCertificates [][]byte) ([]*x509.Certificate, error) {
- if len(rawCertificates) == 0 {
- return nil, errLengthMismatch
- }
- certs := make([]*x509.Certificate, 0, len(rawCertificates))
- for _, rawCert := range rawCertificates {
- cert, err := x509.ParseCertificate(rawCert)
- if err != nil {
- return nil, err
- }
- certs = append(certs, cert)
- }
- return certs, nil
- }
- func verifyClientCert(rawCertificates [][]byte, roots *x509.CertPool) (chains [][]*x509.Certificate, err error) {
- certificate, err := loadCerts(rawCertificates)
- if err != nil {
- return nil, err
- }
- intermediateCAPool := x509.NewCertPool()
- for _, cert := range certificate[1:] {
- intermediateCAPool.AddCert(cert)
- }
- opts := x509.VerifyOptions{
- Roots: roots,
- CurrentTime: time.Now(),
- Intermediates: intermediateCAPool,
- KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
- }
- return certificate[0].Verify(opts)
- }
- func verifyServerCert(rawCertificates [][]byte, roots *x509.CertPool, serverName string) (chains [][]*x509.Certificate, err error) {
- certificate, err := loadCerts(rawCertificates)
- if err != nil {
- return nil, err
- }
- intermediateCAPool := x509.NewCertPool()
- for _, cert := range certificate[1:] {
- intermediateCAPool.AddCert(cert)
- }
- opts := x509.VerifyOptions{
- Roots: roots,
- CurrentTime: time.Now(),
- DNSName: serverName,
- Intermediates: intermediateCAPool,
- }
- return certificate[0].Verify(opts)
- }
|