mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-14 18:59:08 +02:00
78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package certproof
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"encoding/asn1"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"slices"
|
|
)
|
|
|
|
var errUnsupportedScheme = errors.New("unsupported signature scheme for OS keystore")
|
|
|
|
type sigScheme int
|
|
|
|
const (
|
|
schemeECDSASHA256 sigScheme = iota + 1
|
|
schemeECDSASHA384
|
|
schemeRSAPSSSHA256
|
|
)
|
|
|
|
// schemeFor maps a crypto.Signer request onto the schemes the OS keystores perform.
|
|
func schemeFor(pub crypto.PublicKey, opts crypto.SignerOpts) (sigScheme, error) {
|
|
switch pub.(type) {
|
|
case *ecdsa.PublicKey:
|
|
switch opts.HashFunc() {
|
|
case crypto.SHA256:
|
|
return schemeECDSASHA256, nil
|
|
case crypto.SHA384:
|
|
return schemeECDSASHA384, nil
|
|
}
|
|
case *rsa.PublicKey:
|
|
if pss, ok := opts.(*rsa.PSSOptions); ok && pss.Hash == crypto.SHA256 {
|
|
return schemeRSAPSSSHA256, nil
|
|
}
|
|
}
|
|
return 0, fmt.Errorf("%w: %T with %v", errUnsupportedScheme, pub, opts.HashFunc())
|
|
}
|
|
|
|
// buildChain extends leaf with the issuers found in pool up to a self-signed certificate.
|
|
func buildChain(leaf *x509.Certificate, pool []*x509.Certificate) []*x509.Certificate {
|
|
chain := []*x509.Certificate{leaf}
|
|
current := leaf
|
|
for current.CheckSignatureFrom(current) != nil {
|
|
issuer := issuerIn(current, pool, chain)
|
|
if issuer == nil {
|
|
break
|
|
}
|
|
chain = append(chain, issuer)
|
|
current = issuer
|
|
}
|
|
return chain
|
|
}
|
|
|
|
func issuerIn(cert *x509.Certificate, pool, seen []*x509.Certificate) *x509.Certificate {
|
|
for _, candidate := range pool {
|
|
if slices.ContainsFunc(seen, candidate.Equal) {
|
|
continue
|
|
}
|
|
if cert.CheckSignatureFrom(candidate) == nil {
|
|
return candidate
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ecdsaSignatureASN1 converts the fixed-width r||s form emitted by CNG into the DER form Go verifies.
|
|
func ecdsaSignatureASN1(raw []byte) ([]byte, error) {
|
|
if len(raw) == 0 || len(raw)%2 != 0 {
|
|
return nil, errors.New("malformed raw ECDSA signature")
|
|
}
|
|
half := len(raw) / 2
|
|
return asn1.Marshal(struct{ R, S *big.Int }{new(big.Int).SetBytes(raw[:half]), new(big.Int).SetBytes(raw[half:])})
|
|
}
|