github.com/pion/dtls/v2@v2.2.12/pkg/crypto/signaturehash/signaturehash.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package signaturehash provides the SignatureHashAlgorithm as defined in TLS 1.2
     5  package signaturehash
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/ecdsa"
    10  	"crypto/ed25519"
    11  	"crypto/rsa"
    12  	"crypto/tls"
    13  	"fmt"
    14  
    15  	"github.com/pion/dtls/v2/pkg/crypto/hash"
    16  	"github.com/pion/dtls/v2/pkg/crypto/signature"
    17  )
    18  
    19  // Algorithm is a signature/hash algorithm pairs which may be used in
    20  // digital signatures.
    21  //
    22  // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
    23  type Algorithm struct {
    24  	Hash      hash.Algorithm
    25  	Signature signature.Algorithm
    26  }
    27  
    28  // Algorithms are all the know SignatureHash Algorithms
    29  func Algorithms() []Algorithm {
    30  	return []Algorithm{
    31  		{hash.SHA256, signature.ECDSA},
    32  		{hash.SHA384, signature.ECDSA},
    33  		{hash.SHA512, signature.ECDSA},
    34  		{hash.SHA256, signature.RSA},
    35  		{hash.SHA384, signature.RSA},
    36  		{hash.SHA512, signature.RSA},
    37  		{hash.Ed25519, signature.Ed25519},
    38  	}
    39  }
    40  
    41  // SelectSignatureScheme returns most preferred and compatible scheme.
    42  func SelectSignatureScheme(sigs []Algorithm, privateKey crypto.PrivateKey) (Algorithm, error) {
    43  	for _, ss := range sigs {
    44  		if ss.isCompatible(privateKey) {
    45  			return ss, nil
    46  		}
    47  	}
    48  	return Algorithm{}, errNoAvailableSignatureSchemes
    49  }
    50  
    51  // isCompatible checks that given private key is compatible with the signature scheme.
    52  func (a *Algorithm) isCompatible(privateKey crypto.PrivateKey) bool {
    53  	switch privateKey.(type) {
    54  	case ed25519.PrivateKey:
    55  		return a.Signature == signature.Ed25519
    56  	case *ecdsa.PrivateKey:
    57  		return a.Signature == signature.ECDSA
    58  	case *rsa.PrivateKey:
    59  		return a.Signature == signature.RSA
    60  	default:
    61  		return false
    62  	}
    63  }
    64  
    65  // ParseSignatureSchemes translates []tls.SignatureScheme to []signatureHashAlgorithm.
    66  // It returns default signature scheme list if no SignatureScheme is passed.
    67  func ParseSignatureSchemes(sigs []tls.SignatureScheme, insecureHashes bool) ([]Algorithm, error) {
    68  	if len(sigs) == 0 {
    69  		return Algorithms(), nil
    70  	}
    71  	out := []Algorithm{}
    72  	for _, ss := range sigs {
    73  		sig := signature.Algorithm(ss & 0xFF)
    74  		if _, ok := signature.Algorithms()[sig]; !ok {
    75  			return nil,
    76  				fmt.Errorf("SignatureScheme %04x: %w", ss, errInvalidSignatureAlgorithm)
    77  		}
    78  		h := hash.Algorithm(ss >> 8)
    79  		if _, ok := hash.Algorithms()[h]; !ok || (ok && h == hash.None) {
    80  			return nil, fmt.Errorf("SignatureScheme %04x: %w", ss, errInvalidHashAlgorithm)
    81  		}
    82  		if h.Insecure() && !insecureHashes {
    83  			continue
    84  		}
    85  		out = append(out, Algorithm{
    86  			Hash:      h,
    87  			Signature: sig,
    88  		})
    89  	}
    90  
    91  	if len(out) == 0 {
    92  		return nil, errNoAvailableSignatureSchemes
    93  	}
    94  
    95  	return out, nil
    96  }