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_test 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Changimport ( 20*e7b1675dSTing-Kang Chang "encoding/asn1" 21*e7b1675dSTing-Kang Chang "encoding/hex" 22*e7b1675dSTing-Kang Chang "math/big" 23*e7b1675dSTing-Kang Chang "testing" 24*e7b1675dSTing-Kang Chang 25*e7b1675dSTing-Kang Chang "github.com/google/tink/go/signature/subtle" 26*e7b1675dSTing-Kang Chang "github.com/google/tink/go/subtle/random" 27*e7b1675dSTing-Kang Chang) 28*e7b1675dSTing-Kang Chang 29*e7b1675dSTing-Kang Changtype paramsTestECDSA struct { 30*e7b1675dSTing-Kang Chang hash string 31*e7b1675dSTing-Kang Chang curve string 32*e7b1675dSTing-Kang Chang encoding string 33*e7b1675dSTing-Kang Chang} 34*e7b1675dSTing-Kang Chang 35*e7b1675dSTing-Kang Changfunc TestECDSAEncodeDecodeDER(t *testing.T) { 36*e7b1675dSTing-Kang Chang nTest := 1000 37*e7b1675dSTing-Kang Chang for i := 0; i < nTest; i++ { 38*e7b1675dSTing-Kang Chang sig := newECDSARandomSignature() 39*e7b1675dSTing-Kang Chang encoding := "DER" 40*e7b1675dSTing-Kang Chang encoded, err := sig.EncodeECDSASignature(encoding, "P-256") 41*e7b1675dSTing-Kang Chang if err != nil { 42*e7b1675dSTing-Kang Chang t.Errorf("unexpected error during encoding: %s", err) 43*e7b1675dSTing-Kang Chang } 44*e7b1675dSTing-Kang Chang // first byte is 0x30 45*e7b1675dSTing-Kang Chang if encoded[0] != byte(0x30) { 46*e7b1675dSTing-Kang Chang t.Errorf("first byte is incorrect, expected 48, got %v", encoded[0]) 47*e7b1675dSTing-Kang Chang } 48*e7b1675dSTing-Kang Chang // tag is 2 49*e7b1675dSTing-Kang Chang if encoded[2] != byte(2) || encoded[4+encoded[3]] != byte(2) { 50*e7b1675dSTing-Kang Chang t.Errorf("expect tag to be 2 (integer), got %d and %d", encoded[2], encoded[4+encoded[3]]) 51*e7b1675dSTing-Kang Chang } 52*e7b1675dSTing-Kang Chang // length 53*e7b1675dSTing-Kang Chang if len(encoded) != int(encoded[1])+2 { 54*e7b1675dSTing-Kang Chang t.Errorf("incorrect length, expected %d, got %d", len(encoded), encoded[1]+2) 55*e7b1675dSTing-Kang Chang } 56*e7b1675dSTing-Kang Chang decodedSig, err := subtle.DecodeECDSASignature(encoded, encoding) 57*e7b1675dSTing-Kang Chang if err != nil { 58*e7b1675dSTing-Kang Chang t.Errorf("unexpected error during decoding: %s", err) 59*e7b1675dSTing-Kang Chang } 60*e7b1675dSTing-Kang Chang if decodedSig.R.Cmp(sig.R) != 0 || decodedSig.S.Cmp(sig.S) != 0 { 61*e7b1675dSTing-Kang Chang t.Errorf("decoded signature doesn't match original value") 62*e7b1675dSTing-Kang Chang } 63*e7b1675dSTing-Kang Chang } 64*e7b1675dSTing-Kang Chang} 65*e7b1675dSTing-Kang Chang 66*e7b1675dSTing-Kang Changfunc TestECDSAEncodeDecodeIEEEP1363(t *testing.T) { 67*e7b1675dSTing-Kang Chang nTest := 1000 68*e7b1675dSTing-Kang Chang for i := 0; i < nTest; i++ { 69*e7b1675dSTing-Kang Chang sig := newECDSARandomSignature() 70*e7b1675dSTing-Kang Chang encoding := "IEEE_P1363" 71*e7b1675dSTing-Kang Chang encoded, err := sig.EncodeECDSASignature(encoding, "P-256") 72*e7b1675dSTing-Kang Chang if err != nil { 73*e7b1675dSTing-Kang Chang t.Errorf("unexpected error during encoding: %s", err) 74*e7b1675dSTing-Kang Chang } 75*e7b1675dSTing-Kang Chang if len(encoded) != 64 { 76*e7b1675dSTing-Kang Chang t.Errorf("incorrect length, expected %d, got %d", 64, len(encoded)) 77*e7b1675dSTing-Kang Chang } 78*e7b1675dSTing-Kang Chang if len(sig.R.Bytes()) < 32 { 79*e7b1675dSTing-Kang Chang expectedZeros := 32 - len(sig.R.Bytes()) 80*e7b1675dSTing-Kang Chang for i := 0; i < expectedZeros; i++ { 81*e7b1675dSTing-Kang Chang if encoded[i] != 0 { 82*e7b1675dSTing-Kang Chang t.Errorf("expect byte %d to be 0, got %d. encoded data = %s", i, encoded[i], hex.Dump(encoded)) 83*e7b1675dSTing-Kang Chang } 84*e7b1675dSTing-Kang Chang } 85*e7b1675dSTing-Kang Chang } 86*e7b1675dSTing-Kang Chang if len(sig.S.Bytes()) < 32 { 87*e7b1675dSTing-Kang Chang expectedZeros := 32 - len(sig.S.Bytes()) 88*e7b1675dSTing-Kang Chang for i := 32; i < (32 + expectedZeros); i++ { 89*e7b1675dSTing-Kang Chang if encoded[i] != 0 { 90*e7b1675dSTing-Kang Chang t.Errorf("expect byte %d to be 0, got %d. encoded data = %s", i, encoded[i], hex.Dump(encoded)) 91*e7b1675dSTing-Kang Chang } 92*e7b1675dSTing-Kang Chang } 93*e7b1675dSTing-Kang Chang } 94*e7b1675dSTing-Kang Chang decodedSig, err := subtle.DecodeECDSASignature(encoded, encoding) 95*e7b1675dSTing-Kang Chang if err != nil { 96*e7b1675dSTing-Kang Chang t.Errorf("unexpected error during decoding: %s", err) 97*e7b1675dSTing-Kang Chang } 98*e7b1675dSTing-Kang Chang if decodedSig.R.Cmp(sig.R) != 0 || decodedSig.S.Cmp(sig.S) != 0 { 99*e7b1675dSTing-Kang Chang t.Errorf("decoded signature doesn't match original value") 100*e7b1675dSTing-Kang Chang } 101*e7b1675dSTing-Kang Chang } 102*e7b1675dSTing-Kang Chang} 103*e7b1675dSTing-Kang Chang 104*e7b1675dSTing-Kang Changfunc TestECDSAEncodeWithInvalidInput(t *testing.T) { 105*e7b1675dSTing-Kang Chang sig := newECDSARandomSignature() 106*e7b1675dSTing-Kang Chang _, err := sig.EncodeECDSASignature("UNKNOWN_ENCODING", "P-256") 107*e7b1675dSTing-Kang Chang if err == nil { 108*e7b1675dSTing-Kang Chang t.Errorf("expect an error when encoding is invalid") 109*e7b1675dSTing-Kang Chang } 110*e7b1675dSTing-Kang Chang} 111*e7b1675dSTing-Kang Chang 112*e7b1675dSTing-Kang Changfunc TestECDSADecodeWithInvalidInput(t *testing.T) { 113*e7b1675dSTing-Kang Chang var sig *subtle.ECDSASignature 114*e7b1675dSTing-Kang Chang var encoded []byte 115*e7b1675dSTing-Kang Chang encoding := "DER" 116*e7b1675dSTing-Kang Chang 117*e7b1675dSTing-Kang Chang // modified first byte 118*e7b1675dSTing-Kang Chang sig = newECDSARandomSignature() 119*e7b1675dSTing-Kang Chang encoded, _ = sig.EncodeECDSASignature(encoding, "P-256") 120*e7b1675dSTing-Kang Chang encoded[0] = 0x31 121*e7b1675dSTing-Kang Chang if _, err := subtle.DecodeECDSASignature(encoded, encoding); err == nil { 122*e7b1675dSTing-Kang Chang t.Errorf("expect an error when first byte is not 0x30") 123*e7b1675dSTing-Kang Chang } 124*e7b1675dSTing-Kang Chang // modified tag 125*e7b1675dSTing-Kang Chang sig = newECDSARandomSignature() 126*e7b1675dSTing-Kang Chang encoded, _ = sig.EncodeECDSASignature(encoding, "P-256") 127*e7b1675dSTing-Kang Chang encoded[2] = encoded[2] + 1 128*e7b1675dSTing-Kang Chang if _, err := subtle.DecodeECDSASignature(encoded, encoding); err == nil { 129*e7b1675dSTing-Kang Chang t.Errorf("expect an error when tag is modified") 130*e7b1675dSTing-Kang Chang } 131*e7b1675dSTing-Kang Chang // modified length 132*e7b1675dSTing-Kang Chang sig = newECDSARandomSignature() 133*e7b1675dSTing-Kang Chang encoded, _ = sig.EncodeECDSASignature(encoding, "P-256") 134*e7b1675dSTing-Kang Chang encoded[1] = encoded[1] + 1 135*e7b1675dSTing-Kang Chang if _, err := subtle.DecodeECDSASignature(encoded, encoding); err == nil { 136*e7b1675dSTing-Kang Chang t.Errorf("expect an error when length is modified") 137*e7b1675dSTing-Kang Chang } 138*e7b1675dSTing-Kang Chang // append unused 0s 139*e7b1675dSTing-Kang Chang sig = newECDSARandomSignature() 140*e7b1675dSTing-Kang Chang encoded, _ = sig.EncodeECDSASignature(encoding, "P-256") 141*e7b1675dSTing-Kang Chang tmp := make([]byte, len(encoded)+4) 142*e7b1675dSTing-Kang Chang copy(tmp, encoded) 143*e7b1675dSTing-Kang Chang if _, err := subtle.DecodeECDSASignature(tmp, encoding); err == nil { 144*e7b1675dSTing-Kang Chang t.Errorf("expect an error when unused 0s are appended to signature") 145*e7b1675dSTing-Kang Chang } 146*e7b1675dSTing-Kang Chang // a struct with three numbers 147*e7b1675dSTing-Kang Chang randomStruct := struct{ X, Y, Z *big.Int }{ 148*e7b1675dSTing-Kang Chang X: new(big.Int).SetBytes(random.GetRandomBytes(32)), 149*e7b1675dSTing-Kang Chang Y: new(big.Int).SetBytes(random.GetRandomBytes(32)), 150*e7b1675dSTing-Kang Chang Z: new(big.Int).SetBytes(random.GetRandomBytes(32)), 151*e7b1675dSTing-Kang Chang } 152*e7b1675dSTing-Kang Chang encoded, _ = asn1.Marshal(randomStruct) 153*e7b1675dSTing-Kang Chang if _, err := subtle.DecodeECDSASignature(encoded, encoding); err == nil { 154*e7b1675dSTing-Kang Chang t.Errorf("expect an error when input is not an ECDSASignature") 155*e7b1675dSTing-Kang Chang } 156*e7b1675dSTing-Kang Chang} 157*e7b1675dSTing-Kang Chang 158*e7b1675dSTing-Kang Changfunc TestECDSAValidateParams(t *testing.T) { 159*e7b1675dSTing-Kang Chang params := genECDSAValidParams() 160*e7b1675dSTing-Kang Chang for i := 0; i < len(params); i++ { 161*e7b1675dSTing-Kang Chang if err := subtle.ValidateECDSAParams(params[i].hash, params[i].curve, params[i].encoding); err != nil { 162*e7b1675dSTing-Kang Chang t.Errorf("unexpected error for valid params: %s, i = %d", err, i) 163*e7b1675dSTing-Kang Chang } 164*e7b1675dSTing-Kang Chang } 165*e7b1675dSTing-Kang Chang params = genECDSAInvalidParams() 166*e7b1675dSTing-Kang Chang for i := 0; i < len(params); i++ { 167*e7b1675dSTing-Kang Chang if err := subtle.ValidateECDSAParams(params[i].hash, params[i].curve, params[i].encoding); err == nil { 168*e7b1675dSTing-Kang Chang t.Errorf("expect an error when params are invalid, i = %d", i) 169*e7b1675dSTing-Kang Chang } 170*e7b1675dSTing-Kang Chang } 171*e7b1675dSTing-Kang Chang} 172*e7b1675dSTing-Kang Chang 173*e7b1675dSTing-Kang Changfunc genECDSAInvalidParams() []paramsTestECDSA { 174*e7b1675dSTing-Kang Chang encodings := []string{"DER", "IEEE_P1363"} 175*e7b1675dSTing-Kang Chang testCases := []paramsTestECDSA{ 176*e7b1675dSTing-Kang Chang // invalid encoding 177*e7b1675dSTing-Kang Chang {hash: "SHA256", curve: "NIST_P256", encoding: "UNKNOWN_ENCODING"}, 178*e7b1675dSTing-Kang Chang // invalid hash 179*e7b1675dSTing-Kang Chang {hash: "SHA1", curve: "NIST_P256", encoding: "IEEE_P1363"}, 180*e7b1675dSTing-Kang Chang // invalid curve 181*e7b1675dSTing-Kang Chang {hash: "SHA1", curve: "UNKNOWN_CURVE", encoding: "IEEE_P1363"}, 182*e7b1675dSTing-Kang Chang } 183*e7b1675dSTing-Kang Chang for _, encoding := range encodings { 184*e7b1675dSTing-Kang Chang testCases = append(testCases, 185*e7b1675dSTing-Kang Chang // invalid curve 186*e7b1675dSTing-Kang Chang paramsTestECDSA{hash: "SHA256", curve: "UNKNOWN_CURVE", encoding: encoding}, 187*e7b1675dSTing-Kang Chang // invalid hash: P256 and SHA-512 188*e7b1675dSTing-Kang Chang paramsTestECDSA{hash: "SHA512", curve: "NIST_P256", encoding: encoding}, 189*e7b1675dSTing-Kang Chang // invalid hash: P521 and SHA-256 190*e7b1675dSTing-Kang Chang paramsTestECDSA{hash: "SHA256", curve: "NIST_P521", encoding: encoding}, 191*e7b1675dSTing-Kang Chang // invalid hash: P384 and SHA-256 192*e7b1675dSTing-Kang Chang paramsTestECDSA{hash: "SHA256", curve: "NIST_P384", encoding: encoding}, 193*e7b1675dSTing-Kang Chang ) 194*e7b1675dSTing-Kang Chang } 195*e7b1675dSTing-Kang Chang return testCases 196*e7b1675dSTing-Kang Chang} 197*e7b1675dSTing-Kang Chang 198*e7b1675dSTing-Kang Changfunc genECDSAValidParams() []paramsTestECDSA { 199*e7b1675dSTing-Kang Chang return []paramsTestECDSA{ 200*e7b1675dSTing-Kang Chang {hash: "SHA256", curve: "NIST_P256", encoding: "DER"}, 201*e7b1675dSTing-Kang Chang {hash: "SHA256", curve: "NIST_P256", encoding: "IEEE_P1363"}, 202*e7b1675dSTing-Kang Chang {hash: "SHA384", curve: "NIST_P384", encoding: "DER"}, 203*e7b1675dSTing-Kang Chang {hash: "SHA384", curve: "NIST_P384", encoding: "IEEE_P1363"}, 204*e7b1675dSTing-Kang Chang {hash: "SHA512", curve: "NIST_P384", encoding: "DER"}, 205*e7b1675dSTing-Kang Chang {hash: "SHA512", curve: "NIST_P384", encoding: "IEEE_P1363"}, 206*e7b1675dSTing-Kang Chang {hash: "SHA512", curve: "NIST_P521", encoding: "DER"}, 207*e7b1675dSTing-Kang Chang {hash: "SHA512", curve: "NIST_P521", encoding: "IEEE_P1363"}, 208*e7b1675dSTing-Kang Chang } 209*e7b1675dSTing-Kang Chang} 210*e7b1675dSTing-Kang Chang 211*e7b1675dSTing-Kang Changfunc newECDSARandomSignature() *subtle.ECDSASignature { 212*e7b1675dSTing-Kang Chang r := new(big.Int).SetBytes(random.GetRandomBytes(32)) 213*e7b1675dSTing-Kang Chang s := new(big.Int).SetBytes(random.GetRandomBytes(32)) 214*e7b1675dSTing-Kang Chang return subtle.NewECDSASignature(r, s) 215*e7b1675dSTing-Kang Chang} 216