nagendra modadugu | 4fae542 | 2016-05-10 16:11:54 -0700 | [diff] [blame] | 1 | // Copyright 2016 Google Inc. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://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, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | #include <assert.h> |
| 15 | #include <string.h> |
| 16 | #include <stdlib.h> |
| 17 | #include <stdio.h> |
| 18 | #include <time.h> |
| 19 | #include <ctype.h> |
| 20 | |
| 21 | #include <openssl/ec.h> |
| 22 | #include <openssl/ecdsa.h> |
| 23 | #include <openssl/obj_mac.h> |
| 24 | |
| 25 | #include "cryptoc/p256.h" |
| 26 | #include "cryptoc/p256_ecdsa.h" |
| 27 | #include "cryptoc/p256_prng.h" |
| 28 | |
| 29 | // Turn p256 point into ossl compatible binary array. |
| 30 | // Returns # total bytes. |
| 31 | static int to_oct(const p256_int* x, const p256_int* y, uint8_t* buf) { |
| 32 | buf[0] = 4; |
| 33 | p256_to_bin(x, buf + 1); |
| 34 | p256_to_bin(y, buf + 1 + 32); |
| 35 | return 65; |
| 36 | } |
| 37 | |
| 38 | // Turn p256 r,s into ossl compatible signature array. |
| 39 | // r and s are encoded as mpi ints: |
| 40 | // - leading zeros are stripped. |
| 41 | // - if high bit is set, a leading zero is added (i.e. positive numbers only). |
| 42 | // Returns # total bytes. |
| 43 | static int to_sig(const p256_int* r, const p256_int* s, uint8_t* buf) { |
| 44 | uint8_t* p = buf; |
| 45 | uint8_t tmp_r[32 + 1], tmp_s[32 + 1]; |
| 46 | int size_r = sizeof(tmp_r), size_s = sizeof(tmp_s); |
| 47 | int i; |
| 48 | |
| 49 | tmp_r[0] = 0; |
| 50 | p256_to_bin(r, tmp_r + 1); |
| 51 | tmp_s[0] = 0; |
| 52 | p256_to_bin(s, tmp_s + 1); |
| 53 | |
| 54 | for (i = 0; !tmp_r[i] && i < sizeof(tmp_r); ++i) --size_r; |
| 55 | if (tmp_r[i] & 0x80) ++size_r; |
| 56 | for (i = 0; !tmp_s[i] && i < sizeof(tmp_s); ++i) --size_s; |
| 57 | if (tmp_s[i] & 0x80) ++size_s; |
| 58 | |
| 59 | *p++ = 0x30; // sequence tag |
| 60 | *p++ = 2 + size_r + 2 + size_s; |
| 61 | |
| 62 | *p++ = 0x02; // int tag |
| 63 | *p++ = size_r; |
| 64 | memcpy(p, &tmp_r[sizeof(tmp_r) - size_r], size_r); |
| 65 | p += size_r; |
| 66 | |
| 67 | *p++ = 0x02; // int tag |
| 68 | *p++ = size_s; |
| 69 | memcpy(p, &tmp_s[sizeof(tmp_s) - size_s], size_s); |
| 70 | p += size_s; |
| 71 | |
| 72 | return p - buf; |
| 73 | } |
| 74 | |
| 75 | // Load public key into openssl and verify signature on message. |
| 76 | // Returns 0 on fail. |
| 77 | static int ossl_verify(const p256_int* Gx, const p256_int* Gy, |
| 78 | uint8_t* message, |
| 79 | const p256_int* r, const p256_int* s) { |
| 80 | int result = 0; |
| 81 | |
| 82 | uint8_t pk[65]; |
| 83 | uint8_t sig[72]; |
| 84 | |
| 85 | int siglen, pklen; |
| 86 | |
| 87 | EC_KEY* key = EC_KEY_new(); |
| 88 | EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); |
| 89 | EC_POINT* point = EC_POINT_new(group); |
| 90 | |
| 91 | EC_KEY_set_group(key, group); |
| 92 | |
| 93 | pklen = to_oct(Gx, Gy, pk); |
| 94 | |
| 95 | EC_POINT_oct2point(group, point, pk, pklen, 0); |
| 96 | EC_KEY_set_public_key(key, point); |
| 97 | |
| 98 | siglen = to_sig(r, s, sig); |
| 99 | |
| 100 | result = (ECDSA_verify(0, message, 32, sig, siglen, key) == 1); |
| 101 | |
| 102 | EC_POINT_free(point); |
| 103 | EC_GROUP_free(group); |
| 104 | EC_KEY_free(key); |
| 105 | |
| 106 | return result; |
| 107 | } |
| 108 | |
| 109 | // Create and verify some random signatures against openssl. |
| 110 | // time(NULL) is used as prng seed so repeat runs test different values. |
| 111 | static void random_sigs_test() { |
| 112 | int n; |
| 113 | P256_PRNG_CTX prng; |
| 114 | uint8_t tmp[P256_PRNG_SIZE]; |
| 115 | uint32_t boot_count = time(NULL); |
| 116 | |
| 117 | // Setup deterministic prng. |
| 118 | p256_prng_init(&prng, "random_sigs_test", 16, boot_count); |
| 119 | |
| 120 | for (n = 0; n < 100; ++n) { |
| 121 | p256_int a, b, Gx, Gy; |
| 122 | p256_int r, s; |
| 123 | |
| 124 | // Make up private key |
| 125 | do { |
| 126 | // Pick well distributed random number 0 < a < n. |
| 127 | p256_int p1, p2; |
| 128 | p256_prng_draw(&prng, tmp); |
| 129 | p256_from_bin(tmp, &p1); |
| 130 | p256_prng_draw(&prng, tmp); |
| 131 | p256_from_bin(tmp, &p2); |
| 132 | p256_modmul(&SECP256r1_n, &p1, 0, &p2, &a); |
| 133 | } while (p256_is_zero(&a)); |
| 134 | |
| 135 | // Compute public key; a is our secret key. |
| 136 | p256_base_point_mul(&a, &Gx, &Gy); |
| 137 | |
| 138 | // Pick random message to sign. |
| 139 | p256_prng_draw(&prng, tmp); |
| 140 | p256_from_bin(tmp, &b); |
| 141 | |
| 142 | // Compute signature on b. |
| 143 | p256_ecdsa_sign(&a, &b, &r, &s); |
| 144 | |
| 145 | if (!p256_ecdsa_verify(&Gx, &Gy, &b, &r, &s)) { |
| 146 | printf("random_sigs_test()" |
| 147 | ": p256_ecdsa_verify fail at %d! (boot_count %d)\n", |
| 148 | n, boot_count); |
| 149 | exit(1); |
| 150 | } |
| 151 | |
| 152 | if (!ossl_verify(&Gx, &Gy, tmp, &r, &s)) { |
| 153 | printf("random_sigs_test()" |
| 154 | ": ossl_verify fail at %d! (boot_count %d)\n", |
| 155 | n, boot_count); |
| 156 | exit(1); |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | // Test signature parameter validation. |
| 162 | static void invalid_sigs_test() { |
| 163 | P256_PRNG_CTX prng; |
| 164 | uint8_t tmp[P256_PRNG_SIZE]; |
| 165 | uint32_t boot_count = time(NULL); |
| 166 | |
| 167 | p256_prng_init(&prng, "invalid_sigs_test", 17, boot_count); |
| 168 | |
| 169 | { |
| 170 | p256_int a, b, Gx, Gy; |
| 171 | p256_int r, s; |
| 172 | p256_int one = P256_ONE; |
| 173 | p256_int zero = P256_ZERO; |
| 174 | |
| 175 | (void)one; |
| 176 | (void)zero; |
| 177 | |
| 178 | // Make up private key. |
| 179 | do { |
| 180 | // Pick well distributed random number 0 < a < n. |
| 181 | p256_int p1, p2; |
| 182 | p256_prng_draw(&prng, tmp); |
| 183 | p256_from_bin(tmp, &p1); |
| 184 | p256_prng_draw(&prng, tmp); |
| 185 | p256_from_bin(tmp, &p2); |
| 186 | p256_modmul(&SECP256r1_n, &p1, 0, &p2, &a); |
| 187 | } while (p256_is_zero(&a)); |
| 188 | |
| 189 | // Compute public key; a is our secret key. |
| 190 | p256_base_point_mul(&a, &Gx, &Gy); |
| 191 | |
| 192 | // Pick random message to sign. |
| 193 | p256_prng_draw(&prng, tmp); |
| 194 | p256_from_bin(tmp, &b); |
| 195 | |
| 196 | // Compute signature on b. |
| 197 | p256_ecdsa_sign(&a, &b, &r, &s); |
| 198 | |
| 199 | if (!p256_ecdsa_verify(&Gx, &Gy, &b, &r, &s)) { |
| 200 | printf("invalid_sigs_test()" |
| 201 | ": p256_ecdsa_verify fail! (boot_count %d)\n", |
| 202 | boot_count); |
| 203 | exit(1); |
| 204 | } |
| 205 | |
| 206 | // Case 1: r = 0 % n, s = m |
| 207 | if (p256_ecdsa_verify(&Gx, &Gy, &b, &SECP256r1_n, &b)) { |
| 208 | printf("invalid_sigs_test()" |
| 209 | ": p256_ecdsa_verify didn't fail case 1! (boot_count %d)\n", |
| 210 | boot_count); |
| 211 | exit(1); |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | int main(int argc, char* argv[]) { |
| 217 | random_sigs_test(); |
| 218 | invalid_sigs_test(); |
| 219 | return 0; |
| 220 | } |