1*e7b1675dSTing-Kang Chang// Copyright 2020 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Changpackage subtle 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "bytes" 21*e7b1675dSTing-Kang Chang "crypto/elliptic" 22*e7b1675dSTing-Kang Chang "encoding/asn1" 23*e7b1675dSTing-Kang Chang "fmt" 24*e7b1675dSTing-Kang Chang "math/big" 25*e7b1675dSTing-Kang Chang) 26*e7b1675dSTing-Kang Chang 27*e7b1675dSTing-Kang Chang// asn1encode encodes the given ECDSA signature using ASN.1 encoding. 28*e7b1675dSTing-Kang Changfunc asn1encode(sig *ECDSASignature) ([]byte, error) { 29*e7b1675dSTing-Kang Chang ret, err := asn1.Marshal(*sig) 30*e7b1675dSTing-Kang Chang if err != nil { 31*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("asn.1 encoding failed") 32*e7b1675dSTing-Kang Chang } 33*e7b1675dSTing-Kang Chang return ret, nil 34*e7b1675dSTing-Kang Chang} 35*e7b1675dSTing-Kang Chang 36*e7b1675dSTing-Kang Changvar errAsn1Decoding = fmt.Errorf("asn.1 decoding failed") 37*e7b1675dSTing-Kang Chang 38*e7b1675dSTing-Kang Chang// asn1decode verifies the given ECDSA signature and decodes it if it is valid. 39*e7b1675dSTing-Kang Chang// Since asn1.Unmarshal() doesn't do a strict verification on its input, it will 40*e7b1675dSTing-Kang Chang// accept signatures with trailing data. Thus, we add an additional check to make sure 41*e7b1675dSTing-Kang Chang// that the input follows strict DER encoding: after unmarshalling the signature bytes, 42*e7b1675dSTing-Kang Chang// we marshal the obtained signature object again. Since DER encoding is deterministic, 43*e7b1675dSTing-Kang Chang// we expect that the obtained bytes would be equal to the input. 44*e7b1675dSTing-Kang Changfunc asn1decode(b []byte) (*ECDSASignature, error) { 45*e7b1675dSTing-Kang Chang // parse the signature 46*e7b1675dSTing-Kang Chang sig := new(ECDSASignature) 47*e7b1675dSTing-Kang Chang _, err := asn1.Unmarshal(b, sig) 48*e7b1675dSTing-Kang Chang if err != nil { 49*e7b1675dSTing-Kang Chang return nil, errAsn1Decoding 50*e7b1675dSTing-Kang Chang } 51*e7b1675dSTing-Kang Chang // encode the signature again 52*e7b1675dSTing-Kang Chang encoded, err := asn1.Marshal(*sig) 53*e7b1675dSTing-Kang Chang if err != nil { 54*e7b1675dSTing-Kang Chang return nil, errAsn1Decoding 55*e7b1675dSTing-Kang Chang } 56*e7b1675dSTing-Kang Chang if !bytes.Equal(b, encoded) { 57*e7b1675dSTing-Kang Chang return nil, errAsn1Decoding 58*e7b1675dSTing-Kang Chang } 59*e7b1675dSTing-Kang Chang return sig, nil 60*e7b1675dSTing-Kang Chang} 61*e7b1675dSTing-Kang Chang 62*e7b1675dSTing-Kang Changfunc ieeeSignatureSize(curveName string) (int, error) { 63*e7b1675dSTing-Kang Chang switch curveName { 64*e7b1675dSTing-Kang Chang case elliptic.P256().Params().Name: 65*e7b1675dSTing-Kang Chang return 64, nil 66*e7b1675dSTing-Kang Chang case elliptic.P384().Params().Name: 67*e7b1675dSTing-Kang Chang return 96, nil 68*e7b1675dSTing-Kang Chang case elliptic.P521().Params().Name: 69*e7b1675dSTing-Kang Chang return 132, nil 70*e7b1675dSTing-Kang Chang default: 71*e7b1675dSTing-Kang Chang return 0, fmt.Errorf("ieeeP1363 unsupported curve name: %q", curveName) 72*e7b1675dSTing-Kang Chang } 73*e7b1675dSTing-Kang Chang} 74*e7b1675dSTing-Kang Chang 75*e7b1675dSTing-Kang Changfunc ieeeP1363Encode(sig *ECDSASignature, curveName string) ([]byte, error) { 76*e7b1675dSTing-Kang Chang sigSize, err := ieeeSignatureSize(curveName) 77*e7b1675dSTing-Kang Chang if err != nil { 78*e7b1675dSTing-Kang Chang return nil, err 79*e7b1675dSTing-Kang Chang } 80*e7b1675dSTing-Kang Chang 81*e7b1675dSTing-Kang Chang enc := make([]byte, sigSize) 82*e7b1675dSTing-Kang Chang 83*e7b1675dSTing-Kang Chang // sigR and sigS must be half the size of the signature. If not, we need to pad them with zeros. 84*e7b1675dSTing-Kang Chang offset := 0 85*e7b1675dSTing-Kang Chang if len(sig.R.Bytes()) < (sigSize / 2) { 86*e7b1675dSTing-Kang Chang offset += (sigSize / 2) - len(sig.R.Bytes()) 87*e7b1675dSTing-Kang Chang } 88*e7b1675dSTing-Kang Chang // Copy sigR after any zero-padding. 89*e7b1675dSTing-Kang Chang copy(enc[offset:], sig.R.Bytes()) 90*e7b1675dSTing-Kang Chang 91*e7b1675dSTing-Kang Chang // Skip the bytes of sigR. 92*e7b1675dSTing-Kang Chang offset = sigSize / 2 93*e7b1675dSTing-Kang Chang if len(sig.S.Bytes()) < (sigSize / 2) { 94*e7b1675dSTing-Kang Chang offset += (sigSize / 2) - len(sig.S.Bytes()) 95*e7b1675dSTing-Kang Chang } 96*e7b1675dSTing-Kang Chang // Copy sigS after sigR and any zero-padding. 97*e7b1675dSTing-Kang Chang copy(enc[offset:], sig.S.Bytes()) 98*e7b1675dSTing-Kang Chang 99*e7b1675dSTing-Kang Chang return enc, nil 100*e7b1675dSTing-Kang Chang} 101*e7b1675dSTing-Kang Chang 102*e7b1675dSTing-Kang Changfunc ieeeP1363Decode(encodedBytes []byte) (*ECDSASignature, error) { 103*e7b1675dSTing-Kang Chang if len(encodedBytes) == 0 || len(encodedBytes) > 132 || len(encodedBytes)%2 != 0 { 104*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("ecdsa: Invalid IEEE_P1363 encoded bytes") 105*e7b1675dSTing-Kang Chang } 106*e7b1675dSTing-Kang Chang r := new(big.Int).SetBytes(encodedBytes[:len(encodedBytes)/2]) 107*e7b1675dSTing-Kang Chang s := new(big.Int).SetBytes(encodedBytes[len(encodedBytes)/2:]) 108*e7b1675dSTing-Kang Chang return &ECDSASignature{R: r, S: s}, nil 109*e7b1675dSTing-Kang Chang} 110