mirror of
https://github.com/slackhq/nebula.git
synced 2026-02-14 00:34:22 +01:00
Some checks failed
gofmt / Run gofmt (push) Failing after 3s
smoke-extra / Run extra smoke tests (push) Failing after 2s
smoke / Run multi node smoke test (push) Failing after 3s
Build and test / Build all and test on ubuntu-linux (push) Failing after 2s
Build and test / Build and test on linux with boringcrypto (push) Failing after 3s
Build and test / Build and test on linux with pkcs11 (push) Failing after 2s
Build and test / Build and test on macos-latest (push) Has been cancelled
Build and test / Build and test on windows-latest (push) Has been cancelled
Newly signed P256 based certificates will have their signature clamped to the low-s form. Update CHANGELOG.md
123 lines
2.5 KiB
Go
123 lines
2.5 KiB
Go
package p256
|
|
|
|
import (
|
|
"crypto/elliptic"
|
|
"errors"
|
|
"math/big"
|
|
|
|
"filippo.io/bigmod"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
"golang.org/x/crypto/cryptobyte/asn1"
|
|
)
|
|
|
|
var halfN = new(big.Int).Rsh(elliptic.P256().Params().N, 1)
|
|
var nMod *bigmod.Modulus
|
|
|
|
func init() {
|
|
n, err := bigmod.NewModulus(elliptic.P256().Params().N.Bytes())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
nMod = n
|
|
}
|
|
|
|
func IsNormalized(sig []byte) (bool, error) {
|
|
r, s, err := parseSignature(sig)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return checkLowS(r, s), nil
|
|
}
|
|
|
|
func checkLowS(_, s []byte) bool {
|
|
bigS := new(big.Int).SetBytes(s)
|
|
// Check if S <= (N/2), because we want to include the midpoint in the set of low-s
|
|
return bigS.Cmp(halfN) <= 0
|
|
}
|
|
|
|
func swap(r, s []byte) ([]byte, []byte, error) {
|
|
var err error
|
|
bigS, err := bigmod.NewNat().SetBytes(s, nMod)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
sNormalized := nMod.Nat().Sub(bigS, nMod)
|
|
|
|
return r, sNormalized.Bytes(nMod), nil
|
|
}
|
|
|
|
func Normalize(sig []byte) ([]byte, error) {
|
|
r, s, err := parseSignature(sig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if checkLowS(r, s) {
|
|
return sig, nil
|
|
}
|
|
|
|
newR, newS, err := swap(r, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return encodeSignature(newR, newS)
|
|
}
|
|
|
|
// Swap will change sig between its current form to the opposite high or low form.
|
|
func Swap(sig []byte) ([]byte, error) {
|
|
r, s, err := parseSignature(sig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
newR, newS, err := swap(r, s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return encodeSignature(newR, newS)
|
|
}
|
|
|
|
// parseSignature taken exactly from crypto/ecdsa/ecdsa.go
|
|
func parseSignature(sig []byte) (r, s []byte, err error) {
|
|
var inner cryptobyte.String
|
|
input := cryptobyte.String(sig)
|
|
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
|
!input.Empty() ||
|
|
!inner.ReadASN1Integer(&r) ||
|
|
!inner.ReadASN1Integer(&s) ||
|
|
!inner.Empty() {
|
|
return nil, nil, errors.New("invalid ASN.1")
|
|
}
|
|
return r, s, nil
|
|
}
|
|
|
|
func encodeSignature(r, s []byte) ([]byte, error) {
|
|
var b cryptobyte.Builder
|
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
|
addASN1IntBytes(b, r)
|
|
addASN1IntBytes(b, s)
|
|
})
|
|
return b.Bytes()
|
|
}
|
|
|
|
// addASN1IntBytes encodes in ASN.1 a positive integer represented as
|
|
// a big-endian byte slice with zero or more leading zeroes.
|
|
func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
|
|
for len(bytes) > 0 && bytes[0] == 0 {
|
|
bytes = bytes[1:]
|
|
}
|
|
if len(bytes) == 0 {
|
|
b.SetError(errors.New("invalid integer"))
|
|
return
|
|
}
|
|
b.AddASN1(asn1.INTEGER, func(c *cryptobyte.Builder) {
|
|
if bytes[0]&0x80 != 0 {
|
|
c.AddUint8(0)
|
|
}
|
|
c.AddBytes(bytes)
|
|
})
|
|
}
|