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