98ac46b37d
This change adds an additional signature parsing function which performs additional checks to verify the signature is serialized in a valid DER (and thus, unique) format, instead of allowing the less strict BER signatures that ParseSignature will happily accept. Added additional tests and updated test coverage to reflect changes.
167 lines
5.1 KiB
Go
167 lines
5.1 KiB
Go
// Copyright (c) 2013 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package btcec
|
|
|
|
import (
|
|
"crypto/elliptic"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
)
|
|
|
|
// Errors returned by canonicalPadding.
|
|
var (
|
|
errNegativeValue = errors.New("value may be interpreted as negative")
|
|
errExcessivelyPaddedValue = errors.New("value is excessively padded")
|
|
)
|
|
|
|
// Signature is a type representing an ecdsa signature.
|
|
type Signature struct {
|
|
R *big.Int
|
|
S *big.Int
|
|
}
|
|
|
|
func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) {
|
|
// Originally this code used encoding/asn1 in order to parse the
|
|
// signature, but a number of problems were found with this approach.
|
|
// Despite the fact that signatures are stored as DER, the difference
|
|
// between go's idea of a bignum (and that they have sign) doesn't agree
|
|
// with the openssl one (where they do not). The above is true as of
|
|
// Go 1.1. In the end it was simpler to rewrite the code to explicitly
|
|
// understand the format which is this:
|
|
// 0x30 <length of whole message> <0x02> <length of R> <R> 0x2
|
|
// <length of S> <S>.
|
|
|
|
signature := &Signature{}
|
|
|
|
// minimal message is when both numbers are 1 bytes. adding up to:
|
|
// 0x30 + len + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
|
|
if len(sigStr) < 8 {
|
|
return nil, errors.New("malformed signature: too short")
|
|
}
|
|
// 0x30
|
|
index := 0
|
|
if sigStr[index] != 0x30 {
|
|
return nil, errors.New("malformed signature: no header magic")
|
|
}
|
|
index++
|
|
// length of remaining message
|
|
siglen := sigStr[index]
|
|
index++
|
|
if int(siglen+2) > len(sigStr) {
|
|
return nil, errors.New("malformed signature: bad length")
|
|
}
|
|
// trim the slice we're working on so we only look at what matters.
|
|
sigStr = sigStr[:siglen+2]
|
|
|
|
// 0x02
|
|
if sigStr[index] != 0x02 {
|
|
return nil,
|
|
errors.New("malformed signature: no 1st int marker")
|
|
}
|
|
index++
|
|
|
|
// Length of signature R.
|
|
rLen := int(sigStr[index])
|
|
// must be positive, must be able to fit in another 0x2, <len> <s>
|
|
// hence the -3. We assume that the length must be at least one byte.
|
|
index++
|
|
if rLen <= 0 || rLen > len(sigStr)-index-3 {
|
|
return nil, errors.New("malformed signature: bogus R length")
|
|
}
|
|
|
|
// Then R itself.
|
|
rBytes := sigStr[index : index+rLen]
|
|
if der {
|
|
switch err := canonicalPadding(rBytes); err {
|
|
case errNegativeValue:
|
|
return nil, errors.New("signature R is negative")
|
|
case errExcessivelyPaddedValue:
|
|
return nil, errors.New("signature R is excessively padded")
|
|
}
|
|
}
|
|
signature.R = new(big.Int).SetBytes(rBytes)
|
|
index += rLen
|
|
// 0x02. length already checked in previous if.
|
|
if sigStr[index] != 0x02 {
|
|
return nil, errors.New("malformed signature: no 2nd int marker")
|
|
}
|
|
index++
|
|
|
|
// Length of signature S.
|
|
sLen := int(sigStr[index])
|
|
index++
|
|
// S should be the rest of the string.
|
|
if sLen <= 0 || sLen > len(sigStr)-index {
|
|
return nil, errors.New("malformed signature: bogus S length")
|
|
}
|
|
|
|
// Then S itself.
|
|
sBytes := sigStr[index : index+sLen]
|
|
if der {
|
|
switch err := canonicalPadding(sBytes); err {
|
|
case errNegativeValue:
|
|
return nil, errors.New("signature S is negative")
|
|
case errExcessivelyPaddedValue:
|
|
return nil, errors.New("signature S is excessively padded")
|
|
}
|
|
}
|
|
signature.S = new(big.Int).SetBytes(sBytes)
|
|
index += sLen
|
|
|
|
// sanity check length parsing
|
|
if index != len(sigStr) {
|
|
return nil, fmt.Errorf("malformed signature: bad final length %v != %v",
|
|
index, len(sigStr))
|
|
}
|
|
|
|
// Verify also checks this, but we can be more sure that we parsed
|
|
// correctly if we verify here too.
|
|
// FWIW the ecdsa spec states that R and S must be | 1, N - 1 |
|
|
// but crypto/ecdsa only checks for Sign != 0. Mirror that.
|
|
if signature.R.Sign() != 1 {
|
|
return nil, errors.New("signature R isn't 1 or more")
|
|
}
|
|
if signature.S.Sign() != 1 {
|
|
return nil, errors.New("signature S isn't 1 or more")
|
|
}
|
|
if signature.R.Cmp(curve.Params().N) >= 0 {
|
|
return nil, errors.New("signature R is >= curve.N")
|
|
}
|
|
if signature.S.Cmp(curve.Params().N) >= 0 {
|
|
return nil, errors.New("signature S is >= curve.N")
|
|
}
|
|
|
|
return signature, nil
|
|
}
|
|
|
|
// ParseSignature parses a signature in BER format for the curve type `curve'
|
|
// into a Signature type, perfoming some basic sanity checks. If parsing
|
|
// according to the more strict DER format is needed, use ParseDERSignature.
|
|
func ParseSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
|
|
return parseSig(sigStr, curve, false)
|
|
}
|
|
|
|
// ParseDERSignature parses a signature in DER format for the curve type
|
|
// `curve` into a Signature type. If parsing according to the less strict
|
|
// BER format is needed, use ParseSignature.
|
|
func ParseDERSignature(sigStr []byte, curve elliptic.Curve) (*Signature, error) {
|
|
return parseSig(sigStr, curve, true)
|
|
}
|
|
|
|
// canonicalPadding checks whether a big-endian encoded integer could
|
|
// possibly be misinterpreted as a negative number (even though OpenSSL
|
|
// treats all numbers as unsigned), or if there is any unnecessary
|
|
// leading zero padding.
|
|
func canonicalPadding(b []byte) error {
|
|
switch {
|
|
case b[0]&0x80 == 0x80:
|
|
return errNegativeValue
|
|
case len(b) > 1 && b[0] == 0x00 && b[1]&0x80 != 0x80:
|
|
return errExcessivelyPaddedValue
|
|
default:
|
|
return nil
|
|
}
|
|
}
|