| // Copyright 2016 Google Inc. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 | #include <assert.h> | 
 | #include <string.h> | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <time.h> | 
 | #include <ctype.h> | 
 |  | 
 | #include <openssl/ec.h> | 
 | #include <openssl/ecdsa.h> | 
 | #include <openssl/obj_mac.h> | 
 |  | 
 | #include "cryptoc/p256.h" | 
 | #include "cryptoc/p256_ecdsa.h" | 
 | #include "cryptoc/p256_prng.h" | 
 |  | 
 | // Turn p256 point into ossl compatible binary array. | 
 | // Returns # total bytes. | 
 | static int to_oct(const p256_int* x, const p256_int* y, uint8_t* buf) { | 
 |   buf[0] = 4; | 
 |   p256_to_bin(x, buf + 1); | 
 |   p256_to_bin(y, buf + 1 + 32); | 
 |   return 65; | 
 | } | 
 |  | 
 | // Turn p256 r,s into ossl compatible signature array. | 
 | // r and s are encoded as mpi ints: | 
 | //  - leading zeros are stripped. | 
 | //  - if high bit is set, a leading zero is added (i.e. positive numbers only). | 
 | // Returns # total bytes. | 
 | static int to_sig(const p256_int* r, const p256_int* s, uint8_t* buf) { | 
 |   uint8_t* p = buf; | 
 |   uint8_t tmp_r[32 + 1], tmp_s[32 + 1]; | 
 |   int size_r = sizeof(tmp_r), size_s = sizeof(tmp_s); | 
 |   int i; | 
 |  | 
 |   tmp_r[0] = 0; | 
 |   p256_to_bin(r, tmp_r + 1); | 
 |   tmp_s[0] = 0; | 
 |   p256_to_bin(s, tmp_s + 1); | 
 |  | 
 |   for (i = 0; !tmp_r[i] && i < sizeof(tmp_r); ++i) --size_r; | 
 |   if (tmp_r[i] & 0x80) ++size_r; | 
 |   for (i = 0; !tmp_s[i] && i < sizeof(tmp_s); ++i) --size_s; | 
 |   if (tmp_s[i] & 0x80) ++size_s; | 
 |  | 
 |   *p++ = 0x30;  // sequence tag | 
 |   *p++ = 2 + size_r + 2 + size_s; | 
 |  | 
 |   *p++ = 0x02;  // int tag | 
 |   *p++ = size_r; | 
 |   memcpy(p, &tmp_r[sizeof(tmp_r) - size_r], size_r); | 
 |   p += size_r; | 
 |  | 
 |   *p++ = 0x02;  // int tag | 
 |   *p++ = size_s; | 
 |   memcpy(p, &tmp_s[sizeof(tmp_s) - size_s], size_s); | 
 |   p += size_s; | 
 |  | 
 |   return p - buf; | 
 | } | 
 |  | 
 | // Load public key into openssl and verify signature on message. | 
 | // Returns 0 on fail. | 
 | static int ossl_verify(const p256_int* Gx, const p256_int* Gy, | 
 |                        uint8_t* message, | 
 |                        const p256_int* r, const p256_int* s) { | 
 |   int result = 0; | 
 |  | 
 |   uint8_t pk[65]; | 
 |   uint8_t sig[72]; | 
 |  | 
 |   int siglen, pklen; | 
 |  | 
 |   EC_KEY* key = EC_KEY_new(); | 
 |   EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); | 
 |   EC_POINT* point = EC_POINT_new(group); | 
 |  | 
 |   EC_KEY_set_group(key, group); | 
 |  | 
 |   pklen = to_oct(Gx, Gy, pk); | 
 |  | 
 |   EC_POINT_oct2point(group, point, pk, pklen, 0); | 
 |   EC_KEY_set_public_key(key, point); | 
 |  | 
 |   siglen = to_sig(r, s, sig); | 
 |  | 
 |   result = (ECDSA_verify(0, message, 32, sig, siglen, key) == 1); | 
 |  | 
 |   EC_POINT_free(point); | 
 |   EC_GROUP_free(group); | 
 |   EC_KEY_free(key); | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | // Create and verify some random signatures against openssl. | 
 | // time(NULL) is used as prng seed so repeat runs test different values. | 
 | static void random_sigs_test() { | 
 |   int n; | 
 |   P256_PRNG_CTX prng; | 
 |   uint8_t tmp[P256_PRNG_SIZE]; | 
 |   uint32_t boot_count = time(NULL); | 
 |  | 
 |   // Setup deterministic prng. | 
 |   p256_prng_init(&prng, "random_sigs_test", 16, boot_count); | 
 |  | 
 |   for (n = 0; n < 100; ++n) { | 
 |     p256_int a, b, Gx, Gy; | 
 |     p256_int r, s; | 
 |  | 
 |     // Make up private key | 
 |     do { | 
 |       // Pick well distributed random number 0 < a < n. | 
 |       p256_int p1, p2; | 
 |       p256_prng_draw(&prng, tmp); | 
 |       p256_from_bin(tmp, &p1); | 
 |       p256_prng_draw(&prng, tmp); | 
 |       p256_from_bin(tmp, &p2); | 
 |       p256_modmul(&SECP256r1_n, &p1, 0, &p2, &a); | 
 |     } while (p256_is_zero(&a)); | 
 |  | 
 |     // Compute public key; a is our secret key. | 
 |     p256_base_point_mul(&a, &Gx, &Gy); | 
 |  | 
 |     // Pick random message to sign. | 
 |     p256_prng_draw(&prng, tmp); | 
 |     p256_from_bin(tmp, &b); | 
 |  | 
 |     // Compute signature on b. | 
 |     p256_ecdsa_sign(&a, &b, &r, &s); | 
 |  | 
 |     if (!p256_ecdsa_verify(&Gx, &Gy, &b, &r, &s)) { | 
 |       printf("random_sigs_test()" | 
 |              ": p256_ecdsa_verify fail at %d! (boot_count %d)\n", | 
 |              n, boot_count); | 
 |       exit(1); | 
 |     } | 
 |  | 
 |     if (!ossl_verify(&Gx, &Gy, tmp, &r, &s)) { | 
 |       printf("random_sigs_test()" | 
 |              ": ossl_verify fail at %d! (boot_count %d)\n", | 
 |              n, boot_count); | 
 |       exit(1); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // Test signature parameter validation. | 
 | static void invalid_sigs_test() { | 
 |   P256_PRNG_CTX prng; | 
 |   uint8_t tmp[P256_PRNG_SIZE]; | 
 |   uint32_t boot_count = time(NULL); | 
 |  | 
 |   p256_prng_init(&prng, "invalid_sigs_test", 17, boot_count); | 
 |  | 
 |   { | 
 |     p256_int a, b, Gx, Gy; | 
 |     p256_int r, s; | 
 |     p256_int one = P256_ONE; | 
 |     p256_int zero = P256_ZERO; | 
 |  | 
 |     (void)one; | 
 |     (void)zero; | 
 |  | 
 |     // Make up private key. | 
 |     do { | 
 |       // Pick well distributed random number 0 < a < n. | 
 |       p256_int p1, p2; | 
 |       p256_prng_draw(&prng, tmp); | 
 |       p256_from_bin(tmp, &p1); | 
 |       p256_prng_draw(&prng, tmp); | 
 |       p256_from_bin(tmp, &p2); | 
 |       p256_modmul(&SECP256r1_n, &p1, 0, &p2, &a); | 
 |     } while (p256_is_zero(&a)); | 
 |  | 
 |     // Compute public key; a is our secret key. | 
 |     p256_base_point_mul(&a, &Gx, &Gy); | 
 |  | 
 |     // Pick random message to sign. | 
 |     p256_prng_draw(&prng, tmp); | 
 |     p256_from_bin(tmp, &b); | 
 |  | 
 |     // Compute signature on b. | 
 |     p256_ecdsa_sign(&a, &b, &r, &s); | 
 |  | 
 |     if (!p256_ecdsa_verify(&Gx, &Gy, &b, &r, &s)) { | 
 |       printf("invalid_sigs_test()" | 
 |              ": p256_ecdsa_verify fail! (boot_count %d)\n", | 
 |              boot_count); | 
 |       exit(1); | 
 |     } | 
 |  | 
 |     // Case 1: r = 0 % n, s = m | 
 |     if (p256_ecdsa_verify(&Gx, &Gy, &b, &SECP256r1_n, &b)) { | 
 |       printf("invalid_sigs_test()" | 
 |              ": p256_ecdsa_verify didn't fail case 1! (boot_count %d)\n", | 
 |              boot_count); | 
 |       exit(1); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | int main(int argc, char* argv[]) { | 
 |   random_sigs_test(); | 
 |   invalid_sigs_test(); | 
 |   return 0; | 
 | } |