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 #include "./wycheproof_util.h"
16
17 #include <stdlib.h>
18
19 #include <algorithm>
20
21 #include <openssl/bn.h>
22 #include <openssl/digest.h>
23 #include <openssl/ec.h>
24 #include <openssl/nid.h>
25
26 #include "./file_test.h"
27
28
IsValid(const std::vector<std::string> & acceptable_flags) const29 bool WycheproofResult::IsValid(
30 const std::vector<std::string> &acceptable_flags) const {
31 switch (raw_result) {
32 case WycheproofRawResult::kValid:
33 return true;
34 case WycheproofRawResult::kInvalid:
35 return false;
36 case WycheproofRawResult::kAcceptable:
37 for (const auto &flag : flags) {
38 if (std::find(acceptable_flags.begin(), acceptable_flags.end(), flag) ==
39 acceptable_flags.end()) {
40 return false;
41 }
42 }
43 return true;
44 }
45
46 abort();
47 }
48
GetWycheproofResult(FileTest * t,WycheproofResult * out)49 bool GetWycheproofResult(FileTest *t, WycheproofResult *out) {
50 std::string result;
51 if (!t->GetAttribute(&result, "result")) {
52 return false;
53 }
54 if (result == "valid") {
55 out->raw_result = WycheproofRawResult::kValid;
56 } else if (result == "invalid") {
57 out->raw_result = WycheproofRawResult::kInvalid;
58 } else if (result == "acceptable") {
59 out->raw_result = WycheproofRawResult::kAcceptable;
60 } else {
61 t->PrintLine("Bad result string '%s'", result.c_str());
62 return false;
63 }
64
65 out->flags.clear();
66 if (t->HasAttribute("flags")) {
67 std::string flags = t->GetAttributeOrDie("flags");
68 size_t idx = 0;
69 while (idx < flags.size()) {
70 size_t comma = flags.find(',', idx);
71 if (comma == std::string::npos) {
72 comma = flags.size();
73 }
74 out->flags.push_back(flags.substr(idx, comma - idx));
75 idx = comma + 1;
76 }
77 }
78 return true;
79 }
80
GetWycheproofDigest(FileTest * t,const char * key,bool instruction)81 const EVP_MD *GetWycheproofDigest(FileTest *t, const char *key,
82 bool instruction) {
83 std::string name;
84 bool ok =
85 instruction ? t->GetInstruction(&name, key) : t->GetAttribute(&name, key);
86 if (!ok) {
87 return nullptr;
88 }
89 if (name == "SHA-1") {
90 return EVP_sha1();
91 }
92 if (name == "SHA-224") {
93 return EVP_sha224();
94 }
95 if (name == "SHA-256") {
96 return EVP_sha256();
97 }
98 if (name == "SHA-384") {
99 return EVP_sha384();
100 }
101 if (name == "SHA-512") {
102 return EVP_sha512();
103 }
104 t->PrintLine("Unknown digest '%s'", name.c_str());
105 return nullptr;
106 }
107
GetWycheproofCurve(FileTest * t,const char * key,bool instruction)108 bssl::UniquePtr<EC_GROUP> GetWycheproofCurve(FileTest *t, const char *key,
109 bool instruction) {
110 std::string name;
111 bool ok =
112 instruction ? t->GetInstruction(&name, key) : t->GetAttribute(&name, key);
113 if (!ok) {
114 return nullptr;
115 }
116 int nid;
117 if (name == "secp224r1") {
118 nid = NID_secp224r1;
119 } else if (name == "secp256r1") {
120 nid = NID_X9_62_prime256v1;
121 } else if (name == "secp384r1") {
122 nid = NID_secp384r1;
123 } else if (name == "secp521r1") {
124 nid = NID_secp521r1;
125 } else {
126 t->PrintLine("Unknown curve '%s'", name.c_str());
127 return nullptr;
128 }
129 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(nid));
130 }
131
GetWycheproofBIGNUM(FileTest * t,const char * key,bool instruction)132 bssl::UniquePtr<BIGNUM> GetWycheproofBIGNUM(FileTest *t, const char *key,
133 bool instruction) {
134 std::string value;
135 bool ok = instruction ? t->GetInstruction(&value, key)
136 : t->GetAttribute(&value, key);
137 if (!ok) {
138 return nullptr;
139 }
140 BIGNUM *bn = nullptr;
141 if (BN_hex2bn(&bn, value.c_str()) != static_cast<int>(value.size())) {
142 BN_free(bn);
143 t->PrintLine("Could not decode value '%s'", value.c_str());
144 return nullptr;
145 }
146 bssl::UniquePtr<BIGNUM> ret(bn);
147 if (!value.empty()) {
148 // If the high bit is one, this is a negative number in Wycheproof.
149 // Wycheproof's tests generally mimic Java APIs, including all their
150 // mistakes. See
151 // https://github.com/google/wycheproof/blob/0329f5b751ef102bd6b7b7181b6e049522a887f5/java/com/google/security/wycheproof/JsonUtil.java#L62.
152 if ('0' > value[0] || value[0] > '7') {
153 bssl::UniquePtr<BIGNUM> tmp(BN_new());
154 if (!tmp ||
155 !BN_set_bit(tmp.get(), value.size() * 4) ||
156 !BN_sub(ret.get(), ret.get(), tmp.get())) {
157 return nullptr;
158 }
159 }
160 }
161 return ret;
162 }
163