Home | History | Annotate | Download | only in fipstools
      1 /* Copyright (c) 2018, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 // cavp_kas_test processes NIST CAVP ECC KAS test vector request files and
     16 // emits the corresponding response.
     17 
     18 #include <vector>
     19 
     20 #include <openssl/bn.h>
     21 #include <openssl/crypto.h>
     22 #include <openssl/digest.h>
     23 #include <openssl/ecdh.h>
     24 #include <openssl/ecdsa.h>
     25 #include <openssl/ec_key.h>
     26 #include <openssl/err.h>
     27 #include <openssl/nid.h>
     28 
     29 #include "../crypto/internal.h"
     30 #include "../crypto/test/file_test.h"
     31 #include "cavp_test_util.h"
     32 
     33 
     34 static bool TestKAS(FileTest *t, void *arg) {
     35   const bool validate = *reinterpret_cast<bool *>(arg);
     36 
     37   int nid = NID_undef;
     38   const EVP_MD *md = nullptr;
     39 
     40   if (t->HasInstruction("EB - SHA224")) {
     41     nid = NID_secp224r1;
     42     md = EVP_sha224();
     43   } else if (t->HasInstruction("EC - SHA256")) {
     44     nid = NID_X9_62_prime256v1;
     45     md = EVP_sha256();
     46   } else if (t->HasInstruction("ED - SHA384")) {
     47     nid = NID_secp384r1;
     48     md = EVP_sha384();
     49   } else if (t->HasInstruction("EE - SHA512")) {
     50     nid = NID_secp521r1;
     51     md = EVP_sha512();
     52   } else {
     53     return false;
     54   }
     55 
     56   if (!t->HasAttribute("COUNT")) {
     57     return false;
     58   }
     59 
     60   bssl::UniquePtr<BIGNUM> their_x(GetBIGNUM(t, "QeCAVSx"));
     61   bssl::UniquePtr<BIGNUM> their_y(GetBIGNUM(t, "QeCAVSy"));
     62   bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
     63   bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
     64   if (!their_x || !their_y || !ec_key || !ctx) {
     65     return false;
     66   }
     67 
     68   const EC_GROUP *const group = EC_KEY_get0_group(ec_key.get());
     69   bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
     70   if (!their_point ||
     71       !EC_POINT_set_affine_coordinates_GFp(
     72           group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
     73     return false;
     74   }
     75 
     76   if (validate) {
     77     bssl::UniquePtr<BIGNUM> our_k(GetBIGNUM(t, "deIUT"));
     78     if (!our_k ||
     79         !EC_KEY_set_private_key(ec_key.get(), our_k.get()) ||
     80         // These attributes are ignored.
     81         !t->HasAttribute("QeIUTx") ||
     82         !t->HasAttribute("QeIUTy")) {
     83       return false;
     84     }
     85   } else if (!EC_KEY_generate_key(ec_key.get())) {
     86     return false;
     87   }
     88 
     89   constexpr size_t kMaxCurveFieldBits = 521;
     90   uint8_t shared_bytes[(kMaxCurveFieldBits + 7)/8];
     91   const int shared_bytes_len =
     92       ECDH_compute_key(shared_bytes, sizeof(shared_bytes), their_point.get(),
     93                        ec_key.get(), nullptr);
     94 
     95   uint8_t digest[EVP_MAX_MD_SIZE];
     96   unsigned digest_len;
     97   if (shared_bytes_len < 0 ||
     98       !EVP_Digest(shared_bytes, shared_bytes_len, digest, &digest_len, md,
     99                   nullptr)) {
    100     return false;
    101   }
    102 
    103   if (validate) {
    104     std::vector<uint8_t> expected_shared_bytes;
    105     if (!t->GetBytes(&expected_shared_bytes, "CAVSHashZZ")) {
    106       return false;
    107     }
    108     const bool ok =
    109         digest_len == expected_shared_bytes.size() &&
    110         OPENSSL_memcmp(digest, expected_shared_bytes.data(), digest_len) == 0;
    111 
    112     printf("%sIUTHashZZ = %s\r\nResult = %c\r\n\r\n\r\n",
    113            t->CurrentTestToString().c_str(),
    114            EncodeHex(digest, digest_len).c_str(), ok ? 'P' : 'F');
    115   } else {
    116     const EC_POINT *pub = EC_KEY_get0_public_key(ec_key.get());
    117     bssl::UniquePtr<BIGNUM> x(BN_new());
    118     bssl::UniquePtr<BIGNUM> y(BN_new());
    119     if (!x || !y ||
    120         !EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
    121                                              ctx.get())) {
    122       return false;
    123     }
    124     bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
    125     bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
    126 
    127     printf("%sQeIUTx = %s\r\nQeIUTy = %s\r\nHashZZ = %s\r\n",
    128            t->CurrentTestToString().c_str(), x_hex.get(), y_hex.get(),
    129            EncodeHex(digest, digest_len).c_str());
    130   }
    131 
    132   return true;
    133 }
    134 
    135 int cavp_kas_test_main(int argc, char **argv) {
    136   if (argc != 3) {
    137     fprintf(stderr, "usage: %s (validity|function) <test file>\n",
    138             argv[0]);
    139     return 1;
    140   }
    141 
    142   bool validity;
    143   if (strcmp(argv[1], "validity") == 0) {
    144     validity = true;
    145   } else if (strcmp(argv[1], "function") == 0) {
    146     validity = false;
    147   } else {
    148     fprintf(stderr, "Unknown test type: %s\n", argv[1]);
    149     return 1;
    150   }
    151 
    152   FileTest::Options opts;
    153   opts.path = argv[2];
    154   opts.arg = &validity;
    155   opts.callback = TestKAS;
    156   opts.silent = true;
    157   opts.comment_callback = EchoComment;
    158   opts.is_kas_test = true;
    159   return FileTestMain(opts);
    160 }
    161