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 98 99 100 101
|
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
// Package signaturehash provides the SignatureHashAlgorithm as defined in TLS 1.2
package signaturehash
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/tls"
"fmt"
"github.com/pion/dtls/v3/pkg/crypto/hash"
"github.com/pion/dtls/v3/pkg/crypto/signature"
)
// Algorithm is a signature/hash algorithm pairs which may be used in
// digital signatures.
//
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
type Algorithm struct {
Hash hash.Algorithm
Signature signature.Algorithm
}
// Algorithms are all the know SignatureHash Algorithms.
func Algorithms() []Algorithm {
return []Algorithm{
{hash.SHA256, signature.ECDSA},
{hash.SHA384, signature.ECDSA},
{hash.SHA512, signature.ECDSA},
{hash.SHA256, signature.RSA},
{hash.SHA384, signature.RSA},
{hash.SHA512, signature.RSA},
{hash.Ed25519, signature.Ed25519},
}
}
// SelectSignatureScheme returns most preferred and compatible scheme.
func SelectSignatureScheme(sigs []Algorithm, privateKey crypto.PrivateKey) (Algorithm, error) {
signer, ok := privateKey.(crypto.Signer)
if !ok {
return Algorithm{}, errInvalidPrivateKey
}
for _, ss := range sigs {
if ss.isCompatible(signer) {
return ss, nil
}
}
return Algorithm{}, errNoAvailableSignatureSchemes
}
// isCompatible checks that given private key is compatible with the signature scheme.
func (a *Algorithm) isCompatible(signer crypto.Signer) bool {
switch signer.Public().(type) {
case ed25519.PublicKey:
return a.Signature == signature.Ed25519
case *ecdsa.PublicKey:
return a.Signature == signature.ECDSA
case *rsa.PublicKey:
return a.Signature == signature.RSA
default:
return false
}
}
// ParseSignatureSchemes translates []tls.SignatureScheme to []signatureHashAlgorithm.
// It returns default signature scheme list if no SignatureScheme is passed.
func ParseSignatureSchemes(sigs []tls.SignatureScheme, insecureHashes bool) ([]Algorithm, error) {
if len(sigs) == 0 {
return Algorithms(), nil
}
out := []Algorithm{}
for _, ss := range sigs {
sig := signature.Algorithm(ss & 0xFF)
if _, ok := signature.Algorithms()[sig]; !ok {
return nil,
fmt.Errorf("SignatureScheme %04x: %w", ss, errInvalidSignatureAlgorithm)
}
h := hash.Algorithm(ss >> 8)
if _, ok := hash.Algorithms()[h]; !ok || (ok && h == hash.None) {
return nil, fmt.Errorf("SignatureScheme %04x: %w", ss, errInvalidHashAlgorithm)
}
if h.Insecure() && !insecureHashes {
continue
}
out = append(out, Algorithm{
Hash: h,
Signature: sig,
})
}
if len(out) == 0 {
return nil, errNoAvailableSignatureSchemes
}
return out, nil
}
|