blob: 059e1a30c003fc85b0f5bc3f2fb3d5f103574574 [file] [log] [blame]
// 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;
}