File: signaturehash.go

package info (click to toggle)
golang-github-pion-dtls-v3 3.0.7-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,124 kB
  • sloc: makefile: 4
file content (101 lines) | stat: -rw-r--r-- 2,740 bytes parent folder | download
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
}