| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build !android,linux,amd64,cgo,!noopenssl openssl,cgo |
| |
| package security |
| |
| import ( |
| "bytes" |
| "crypto/ecdsa" |
| "crypto/elliptic" |
| "crypto/rand" |
| "reflect" |
| "testing" |
| ) |
| |
| var opensslKey *bmkey |
| |
| func init() { |
| key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
| if err != nil { |
| panic(err) |
| } |
| signer, err := newOpenSSLSigner(key) |
| if err != nil { |
| panic(err) |
| } |
| signature, err := signer.Sign(purpose, message) |
| if err != nil { |
| panic(err) |
| } |
| opensslKey = &bmkey{signer, signature} |
| } |
| |
| func BenchmarkSign_ECDSA_OpenSSL(b *testing.B) { |
| benchmarkSign(opensslKey, b) |
| } |
| |
| func BenchmarkVerify_ECDSA_OpenSSL(b *testing.B) { |
| benchmarkVerify(opensslKey, b) |
| } |
| |
| func TestOpenSSLCompatibility(t *testing.T) { |
| t.Log(openssl_version()) |
| var ( |
| purpose = make([]byte, 5) |
| message = make([]byte, 100) |
| ntests = 0 |
| ) |
| if _, err := rand.Reader.Read(purpose); err != nil { |
| t.Error(err) |
| } |
| if _, err := rand.Reader.Read(message); err != nil { |
| t.Error(err) |
| } |
| for curveidx, curve := range []elliptic.Curve{elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521()} { |
| key, err := ecdsa.GenerateKey(curve, rand.Reader) |
| if err != nil { |
| t.Errorf("Failed to generate key #%d", curveidx) |
| continue |
| } |
| golang, err := newGoStdlibSigner(key) |
| if err != nil { |
| t.Error(err) |
| continue |
| } |
| openssl, err := newOpenSSLSigner(key) |
| if err != nil { |
| t.Error(err) |
| continue |
| } |
| signers := []Signer{golang, openssl} |
| // Sanity check: Ensure that the implementations are indeed different. |
| for i := 0; i < len(signers); i++ { |
| si := signers[i] |
| for j := i + 1; j < len(signers); j++ { |
| sj := signers[j] |
| if pi, pj := si.PublicKey(), sj.PublicKey(); reflect.TypeOf(pi) == reflect.TypeOf(pj) { |
| t.Errorf("PublicKey %d and %d have the same type: %T", i, j, pi) |
| } |
| } |
| } |
| // Signatures by any one implementation should be by all. |
| for _, signer := range signers { |
| signature, err := signer.Sign(purpose, message) |
| if err != nil { |
| t.Errorf("Curve #%d: Signature with %T failed: %v", curveidx, signer.PublicKey(), err) |
| continue |
| } |
| for _, verifier := range signers { |
| pub := verifier.PublicKey() |
| if !signature.Verify(pub, message) { |
| t.Errorf("Curve #%d: Messaged signed by %T not verified by %T", curveidx, signer, pub) |
| continue |
| } |
| ntests++ |
| } |
| } |
| // All the metadata functions should return the same results. |
| pub0 := signers[0].PublicKey() |
| bin0, err := pub0.MarshalBinary() |
| if err != nil { |
| t.Errorf("Curve #%d: %T.MarshalBinary failed: %v", curveidx, pub0, err) |
| continue |
| } |
| for _, signer := range signers[1:] { |
| pubi := signer.PublicKey() |
| if got, want := pubi.String(), pub0.String(); got != want { |
| t.Errorf("Curve #%d: String for %T and %T do not match (%q vs %q)", curveidx, pubi, pub0, got, want) |
| } |
| bini, err := pubi.MarshalBinary() |
| if err != nil { |
| t.Errorf("Curve #%d: %T.MarshalBinary failed: %v", curveidx, pubi, err) |
| continue |
| } |
| if !bytes.Equal(bin0, bini) { |
| t.Errorf("Curve #%d: MarshalBinary for %T and %T do not match (%v vs %v)", curveidx, pubi, pub0, bini, bin0) |
| } |
| if got, want := pubi.hash(), pub0.hash(); got != want { |
| t.Errorf("Curve #%d: hash for %T(=%v) and %T(=%v) do not match", curveidx, pubi, got, pub0, want) |
| } |
| } |
| } |
| // Silly sanity check to help ensure that these nested loops weren't short circuited |
| if got, want := ntests, 16; got != want { // 2 types of keys => 4 tests * 4 curves |
| t.Errorf("%d combinations of tests succeeded, expected %d", got, want) |
| } |
| } |