• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_crypto/ecdsa.h"
16 
17 #include <cstring>
18 
19 #include "gtest/gtest.h"
20 
21 namespace pw::crypto::ecdsa {
22 namespace {
23 
24 #define AS_BYTES(s) as_bytes(span(s, sizeof(s) - 1))
25 
26 #define ASSERT_OK(expr) ASSERT_EQ(OkStatus(), expr)
27 #define ASSERT_FAIL(expr) ASSERT_NE(OkStatus(), expr)
28 
29 // TEST_DIGEST/PUBKEY/SIGNATURE are generated using the pkey/ecdsa.c
30 // example in Mbed TLS.
31 
32 // The SHA256 digest of "Hello, Pigweed!", 32 bytes.
33 #define TEST_DIGEST                                                  \
34   "\x8D\xCE\x14\xEE\x2C\xD9\xFD\x9B\xBD\x8C\x8D\x57\x68\x50\x2C\x2F" \
35   "\xFB\xB3\x52\x36\xCE\x93\x47\x1B\x80\xFC\xA4\x7D\xB5\xF8\x41\x9D"
36 
37 // The public key in uncompressed form, 65 bytes.
38 #define TEST_PUBKEY                                                  \
39   "\x04"                                                             \
40   "\xD1\x82\x2E\x6A\xD2\x4B\x2A\x80\x2E\x8F\xBC\x03\x00\x95\x11\xF9" \
41   "\x81\x24\xA7\x3C\x45\xC8\xBA\xDD\x5F\x77\x1C\xC3\x71\x8B\xB2\xE9" \
42   "\x3A\x0A\x84\xFF\xEA\x13\xC2\x27\xD2\xCF\x42\x7D\xA5\x95\xD6\x88" \
43   "\xCD\x23\x00\x3F\xF9\xD9\x75\x46\xFF\x58\xE9\xBE\xC3\x74\x13\xB8"
44 
45 // The ECDSA P256 signature of `DIGEST`.
46 #define TEST_SIGNATURE                                               \
47   "\x16\x54\x43\xD4\x00\x07\xC4\xD7\x26\x2E\x3C\xB1\x65\x54\x00\x6A" \
48   "\x6A\x5B\x4A\xBB\x16\x6F\x44\xD0\x91\x3F\xD3\xC2\x50\xAC\x1A\x87" \
49   "\x86\x41\xEE\x56\xDA\x31\xF2\xFF\x38\x3C\xBB\x32\x3E\x2D\xDB\x98" \
50   "\xEA\x05\x9E\x8F\x91\x8E\x0E\x99\xE5\x4F\x32\x13\x92\x7F\x17\x68"
51 
52 // The public key in uncompressed form, missing the header byte.
53 #define MALFORMED_PUBKEY_MISSING_HEADER                              \
54   "\xD1\x82\x2E\x6A\xD2\x4B\x2A\x80\x2E\x8F\xBC\x03\x00\x95\x11\xF9" \
55   "\x81\x24\xA7\x3C\x45\xC8\xBA\xDD\x5F\x77\x1C\xC3\x71\x8B\xB2\xE9" \
56   "\x3A\x0A\x84\xFF\xEA\x13\xC2\x27\xD2\xCF\x42\x7D\xA5\x95\xD6\x88" \
57   "\xCD\x23\x00\x3F\xF9\xD9\x75\x46\xFF\x58\xE9\xBE\xC3\x74\x13\xB8"
58 
59 // The public key in compressed form, wrong the header byte (03 instead of 02).
60 #define MALFORMED_PUBKEY_WRONG_HEADER                                \
61   "\x03"                                                             \
62   "\xD1\x82\x2E\x6A\xD2\x4B\x2A\x80\x2E\x8F\xBC\x03\x00\x95\x11\xF9" \
63   "\x81\x24\xA7\x3C\x45\xC8\xBA\xDD\x5F\x77\x1C\xC3\x71\x8B\xB2\xE9"
64 
65 // Tampered signature (first bit flipped).
66 #define TAMPERED_SIGNATURE                                           \
67   "\x17\x54\x43\xD4\x00\x07\xC4\xD7\x26\x2E\x3C\xB1\x65\x54\x00\x6A" \
68   "\x6A\x5B\x4A\xBB\x16\x6F\x44\xD0\x91\x3F\xD3\xC2\x50\xAC\x1A\x87" \
69   "\x86\x41\xEE\x56\xDA\x31\xF2\xFF\x38\x3C\xBB\x32\x3E\x2D\xDB\x98" \
70   "\xEA\x05\x9E\x8F\x91\x8E\x0E\x99\xE5\x4F\x32\x13\x92\x7F\x17\x68"
71 
72 // Short signature (last byte removed).
73 #define SHORT_SIGNATURE                                              \
74   "\x16\x54\x43\xD4\x00\x07\xC4\xD7\x26\x2E\x3C\xB1\x65\x54\x00\x6A" \
75   "\x6A\x5B\x4A\xBB\x16\x6F\x44\xD0\x91\x3F\xD3\xC2\x50\xAC\x1A\x87" \
76   "\x86\x41\xEE\x56\xDA\x31\xF2\xFF\x38\x3C\xBB\x32\x3E\x2D\xDB\x98" \
77   "\xEA\x05\x9E\x8F\x91\x8E\x0E\x99\xE5\x4F\x32\x13\x92\x7F\x17"
78 
79 // Short digest (last byte removed)
80 #define SHORT_DIGEST                                                 \
81   "\x8D\xCE\x14\xEE\x2C\xD9\xFD\x9B\xBD\x8C\x8D\x57\x68\x50\x2C\x2F" \
82   "\xFB\xB3\x52\x36\xCE\x93\x47\x1B\x80\xFC\xA4\x7D\xB5\xF8\x41"
83 
84 // Tampered digest (first bit flipped)
85 #define TAMPERED_DIGEST                                              \
86   "\x8C\xCE\x14\xEE\x2C\xD9\xFD\x9B\xBD\x8C\x8D\x57\x68\x50\x2C\x2F" \
87   "\xFB\xB3\x52\x36\xCE\x93\x47\x1B\x80\xFC\xA4\x7D\xB5\xF8\x41\x9D"
88 
89 // Tampered public key (last bit flipped).
90 #define TAMPERED_PUBKEY                                              \
91   "\x04"                                                             \
92   "\xD1\x82\x2E\x6A\xD2\x4B\x2A\x80\x2E\x8F\xBC\x03\x00\x95\x11\xF9" \
93   "\x81\x24\xA7\x3C\x45\xC8\xBA\xDD\x5F\x77\x1C\xC3\x71\x8B\xB2\xE9" \
94   "\x3A\x0A\x84\xFF\xEA\x13\xC2\x27\xD2\xCF\x42\x7D\xA5\x95\xD6\x88" \
95   "\xCD\x23\x00\x3F\xF9\xD9\x75\x46\xFF\x58\xE9\xBE\xC3\x74\x13\xB9"
96 
TEST(EcdsaP256,ValidSignature)97 TEST(EcdsaP256, ValidSignature) {
98   ASSERT_OK(VerifyP256Signature(
99       AS_BYTES(TEST_PUBKEY), AS_BYTES(TEST_DIGEST), AS_BYTES(TEST_SIGNATURE)));
100 }
101 
TEST(EcdsaP256,LongerDigestGetsTruncated)102 TEST(EcdsaP256, LongerDigestGetsTruncated) {
103   ASSERT_OK(VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
104                                 AS_BYTES(TEST_DIGEST "extra stuff"),
105                                 AS_BYTES(TEST_SIGNATURE)));
106 }
107 
TEST(EcdsaP256,MalformedPublicKeyMissingHeader)108 TEST(EcdsaP256, MalformedPublicKeyMissingHeader) {
109   ASSERT_EQ(Status::InvalidArgument(),
110             VerifyP256Signature(AS_BYTES(MALFORMED_PUBKEY_MISSING_HEADER),
111                                 AS_BYTES(TEST_DIGEST),
112                                 AS_BYTES(TEST_SIGNATURE)));
113 }
114 
TEST(EcdsaP256,MalformedPublicKeyWrongHeader)115 TEST(EcdsaP256, MalformedPublicKeyWrongHeader) {
116   ASSERT_FAIL(VerifyP256Signature(AS_BYTES(MALFORMED_PUBKEY_WRONG_HEADER),
117                                   AS_BYTES(TEST_DIGEST),
118                                   AS_BYTES(TEST_SIGNATURE)));
119 }
120 
TEST(EcdsaP256,TamperedSignature)121 TEST(EcdsaP256, TamperedSignature) {
122   ASSERT_EQ(Status::Unauthenticated(),
123             VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
124                                 AS_BYTES(TEST_DIGEST),
125                                 AS_BYTES(TAMPERED_SIGNATURE)));
126 }
127 
TEST(EcdsaP256,SignatureTooLong)128 TEST(EcdsaP256, SignatureTooLong) {
129   ASSERT_EQ(Status::InvalidArgument(),
130             VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
131                                 AS_BYTES(TEST_DIGEST),
132                                 AS_BYTES(TEST_SIGNATURE "extra stuff")));
133 }
134 
TEST(EcdsaP256,SignatureTooShort)135 TEST(EcdsaP256, SignatureTooShort) {
136   ASSERT_EQ(Status::InvalidArgument(),
137             VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
138                                 AS_BYTES(TEST_DIGEST),
139                                 AS_BYTES(SHORT_SIGNATURE)));
140 }
141 
TEST(EcdsaP256,DigestTooShort)142 TEST(EcdsaP256, DigestTooShort) {
143   ASSERT_EQ(Status::InvalidArgument(),
144             VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
145                                 AS_BYTES(SHORT_DIGEST),
146                                 AS_BYTES(TEST_SIGNATURE)));
147 }
148 
TEST(EcdsaP256,TamperedDigest)149 TEST(EcdsaP256, TamperedDigest) {
150   ASSERT_EQ(Status::Unauthenticated(),
151             VerifyP256Signature(AS_BYTES(TEST_PUBKEY),
152                                 AS_BYTES(TAMPERED_DIGEST),
153                                 AS_BYTES(TEST_SIGNATURE)));
154 }
155 
TEST(EcdsaP256,TamperedPubkey)156 TEST(EcdsaP256, TamperedPubkey) {
157   ASSERT_FAIL(VerifyP256Signature(AS_BYTES(TAMPERED_PUBKEY),
158                                   AS_BYTES(TEST_DIGEST),
159                                   AS_BYTES(TEST_SIGNATURE)));
160 }
161 
162 }  // namespace
163 }  // namespace pw::crypto::ecdsa
164