Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 /* vim: set ts=2 et sw=2 tw=80: */ | 2 /* vim: set ts=2 et sw=2 tw=80: */ |
3 /* This Source Code Form is subject to the terms of the Mozilla Public | 3 /* This Source Code Form is subject to the terms of the Mozilla Public |
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, | 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ | 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | 6 |
7 #include "nss.h" | 7 #include "nss.h" |
8 #include "keyhi.h" | 8 #include "keyhi.h" |
9 #include "pk11pub.h" | 9 #include "pk11pub.h" |
10 #include "sechash.h" | 10 #include "sechash.h" |
11 #include <memory> | 11 #include <memory> |
12 | 12 |
13 #include "gtest/gtest.h" | 13 #include "gtest/gtest.h" |
14 #include "scoped_ptrs.h" | |
14 | 15 |
15 namespace nss_test { | 16 namespace nss_test { |
16 | |
17 struct TestVector { | |
18 const uint8_t* spki; | |
19 unsigned int spki_len; | |
20 const uint8_t* data; | |
21 unsigned int data_len; | |
22 const uint8_t* sig; | |
23 unsigned int sig_len; | |
ekr-rietveld
2015/11/06 21:31:59
These lengths should be size_t
| |
24 }; | |
25 | 17 |
26 // RSA-PSS test vectors, pss-vect.txt, Example 1: A 1024-bit RSA Key Pair | 18 // RSA-PSS test vectors, pss-vect.txt, Example 1: A 1024-bit RSA Key Pair |
27 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> | 19 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> |
28 const uint8_t kTestVector1Spki[] = { | 20 const uint8_t kTestVector1Spki[] = { |
29 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, | 21 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, |
30 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, | 22 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, |
31 0x81, 0x81, 0x00, 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, 0x9a, 0x51, | 23 0x81, 0x81, 0x00, 0xa5, 0x6e, 0x4a, 0x0e, 0x70, 0x10, 0x17, 0x58, 0x9a, 0x51, |
32 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, | 24 0x87, 0xdc, 0x7e, 0xa8, 0x41, 0xd1, 0x56, 0xf2, 0xec, 0x0e, 0x36, 0xad, 0x52, |
33 0xa4, 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, 0xd8, 0xc5, 0x10, 0x56, | 25 0xa4, 0x4d, 0xfe, 0xb1, 0xe6, 0x1f, 0x7a, 0xd9, 0x91, 0xd8, 0xc5, 0x10, 0x56, |
34 0xff, 0xed, 0xb1, 0x62, 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, 0x94, | 26 0xff, 0xed, 0xb1, 0x62, 0xb4, 0xc0, 0xf2, 0x83, 0xa1, 0x2a, 0x88, 0xa3, 0x94, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 0x99, 0x28, 0x0b, 0x9b, 0x28, 0xf7, 0x9b, 0x04, 0x09, 0x00, 0x0b, 0xe2, 0x5b, | 116 0x99, 0x28, 0x0b, 0x9b, 0x28, 0xf7, 0x9b, 0x04, 0x09, 0x00, 0x0b, 0xe2, 0x5b, |
125 0xbd, 0x96, 0x40, 0x8b, 0xa3, 0xb4, 0x3c, 0xc4, 0x86, 0x18, 0x4d, 0xd1, 0xc8, | 117 0xbd, 0x96, 0x40, 0x8b, 0xa3, 0xb4, 0x3c, 0xc4, 0x86, 0x18, 0x4d, 0xd1, 0xc8, |
126 0xe6, 0x25, 0x53, 0xfa, 0x1a, 0xf4, 0x04, 0x0f, 0x60, 0x66, 0x3d, 0xe7, 0xf5, | 118 0xe6, 0x25, 0x53, 0xfa, 0x1a, 0xf4, 0x04, 0x0f, 0x60, 0x66, 0x3d, 0xe7, 0xf5, |
127 0xe4, 0x9c, 0x04, 0x38, 0x8e, 0x25, 0x7f, 0x1c, 0xe8, 0x9c, 0x95, 0xda, 0xb4, | 119 0xe4, 0x9c, 0x04, 0x38, 0x8e, 0x25, 0x7f, 0x1c, 0xe8, 0x9c, 0x95, 0xda, 0xb4, |
128 0x8a, 0x31, 0x5d, 0x9b, 0x66, 0xb1, 0xb7, 0x62, 0x82, 0x33, 0x87, 0x6f, 0xf2, | 120 0x8a, 0x31, 0x5d, 0x9b, 0x66, 0xb1, 0xb7, 0x62, 0x82, 0x33, 0x87, 0x6f, 0xf2, |
129 0x38, 0x52, 0x30, 0xd0, 0x70, 0xd0, 0x7e, 0x16, 0x66 | 121 0x38, 0x52, 0x30, 0xd0, 0x70, 0xd0, 0x7e, 0x16, 0x66 |
130 }; | 122 }; |
131 | 123 |
132 static unsigned char* toUcharPtr(const uint8_t* v) { | 124 static unsigned char* toUcharPtr(const uint8_t* v) { |
133 return const_cast<unsigned char*>( | 125 return const_cast<unsigned char*>( |
134 static_cast<const unsigned char *>(v)); | 126 static_cast<const unsigned char*>(v)); |
135 } | 127 } |
136 | 128 |
137 class Pkcs11RsaPssTest : public ::testing::Test { | 129 class Pkcs11RsaPssTest : public ::testing::Test { |
138 }; | 130 }; |
139 | 131 |
140 class Pkcs11RsaPssVectorTest : public Pkcs11RsaPssTest { | 132 class Pkcs11RsaPssVectorTest : public Pkcs11RsaPssTest { |
141 public: | 133 public: |
142 Pkcs11RsaPssVectorTest() : tv_(nullptr) {} | 134 void Verify(const uint8_t* spki, size_t spki_len, const uint8_t* data, |
143 | 135 size_t data_len, const uint8_t* sig, size_t sig_len) { |
144 void Init(TestVector* tv) { | |
ekr-rietveld
2015/11/06 21:31:59
const
| |
145 tv_ = tv; | |
146 } | |
147 | |
148 void Verify() { | |
149 // Verify data signed with PSS/SHA-1. | 136 // Verify data signed with PSS/SHA-1. |
150 SECOidTag hashOid = SEC_OID_SHA1; | 137 SECOidTag hashOid = SEC_OID_SHA1; |
151 CK_MECHANISM_TYPE hashMech = CKM_SHA_1; | 138 CK_MECHANISM_TYPE hashMech = CKM_SHA_1; |
152 CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA1; | 139 CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA1; |
153 | 140 |
154 // Set up PSS parameters. | 141 // Set up PSS parameters. |
155 unsigned int hLen = HASH_ResultLenByOidTag(hashOid); | 142 unsigned int hLen = HASH_ResultLenByOidTag(hashOid); |
156 CK_RSA_PKCS_PSS_PARAMS rsaPssParams = { hashMech, mgf, hLen }; | 143 CK_RSA_PKCS_PSS_PARAMS rsaPssParams = { hashMech, mgf, hLen }; |
157 SECItem params = { siBuffer, (unsigned char*)&rsaPssParams, | 144 SECItem params = { siBuffer, |
ekr-rietveld
2015/11/06 21:31:59
Use C++-style casts in C++ code please.
| |
158 sizeof(rsaPssParams) }; | 145 reinterpret_cast<unsigned char*>(&rsaPssParams), |
ekr-rietveld
2015/11/06 21:31:59
Fix indent.
| |
146 sizeof(rsaPssParams) }; | |
159 | 147 |
160 // Import public key. | 148 // Import public key. |
161 SECItem spkiItem = { siBuffer, toUcharPtr(tv_->spki), tv_->spki_len }; | 149 SECItem spkiItem = { siBuffer, toUcharPtr(spki), |
162 CERTSubjectPublicKeyInfo* spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiIte m)); | 150 static_cast<unsigned int>(spki_len) }; |
163 SECKEYPublicKey* pubKey(SECKEY_ExtractPublicKey(spki)); | 151 ScopedCERTSubjectPublicKeyInfo certSpki( |
152 SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); | |
153 ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(certSpki.get())); | |
164 | 154 |
165 // Hash the data. | 155 // Hash the data. |
166 SECItem* hash(SECITEM_AllocItem(nullptr, nullptr, hLen)); | 156 std::vector<uint8_t> hashBuf(hLen); |
167 SECStatus rv = PK11_HashBuf(hashOid, hash->data, toUcharPtr(tv_->data), | 157 SECItem hash = { siBuffer, &hashBuf[0], |
168 tv_->data_len); | 158 static_cast<unsigned int>(hashBuf.size()) }; |
159 SECStatus rv = PK11_HashBuf(hashOid, hash.data, toUcharPtr(data), | |
160 data_len); | |
169 EXPECT_EQ(rv, SECSuccess); | 161 EXPECT_EQ(rv, SECSuccess); |
170 | 162 |
171 // Verify. | 163 // Verify. |
172 CK_MECHANISM_TYPE mech = CKM_RSA_PKCS_PSS; | 164 CK_MECHANISM_TYPE mech = CKM_RSA_PKCS_PSS; |
173 SECItem sig = { siBuffer, toUcharPtr(tv_->sig), tv_->sig_len }; | 165 SECItem sigItem = { siBuffer, toUcharPtr(sig), |
174 rv = PK11_VerifyWithMechanism(pubKey, mech, ¶ms, &sig, hash, nullptr); | 166 static_cast<unsigned int>(sig_len) }; |
167 rv = PK11_VerifyWithMechanism(pubKey.get(), mech, ¶ms, &sigItem, &hash, | |
168 nullptr); | |
175 EXPECT_EQ(rv, SECSuccess); | 169 EXPECT_EQ(rv, SECSuccess); |
176 | |
177 // Cleanup | |
178 SECITEM_FreeItem(hash, PR_TRUE); | |
179 SECKEY_DestroyPublicKey(pubKey); | |
180 SECKEY_DestroySubjectPublicKeyInfo(spki); | |
ekr-rietveld
2015/11/06 21:31:59
Instead, use the types in: https://dxr.mozilla.org
ttaubert
2015/11/09 17:27:17
Oh right, I've used them before for WebCrypto but
| |
181 } | 170 } |
182 | 171 }; |
183 protected: | 172 |
184 TestVector* tv_; | 173 #define PSS_TEST_VECTOR_VERIFY(spki, data, sig) \ |
185 }; | 174 Verify(spki, sizeof(spki), data, sizeof(data), sig, sizeof(sig)); |
186 | 175 |
187 TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) { | 176 TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) { |
188 // Sign data with a 1024-bit RSA key, using PSS/SHA-256. | 177 // Sign data with a 1024-bit RSA key, using PSS/SHA-256. |
189 SECOidTag hashOid = SEC_OID_SHA256; | 178 SECOidTag hashOid = SEC_OID_SHA256; |
190 CK_MECHANISM_TYPE hashMech = CKM_SHA256; | 179 CK_MECHANISM_TYPE hashMech = CKM_SHA256; |
191 CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA256; | 180 CK_RSA_PKCS_MGF_TYPE mgf = CKG_MGF1_SHA256; |
192 PK11RSAGenParams rsaGenParams = { 1024, 0x10001 }; | 181 PK11RSAGenParams rsaGenParams = { 1024, 0x10001 }; |
193 | 182 |
194 // Generate RSA key pair. | 183 // Generate RSA key pair. |
195 PK11SlotInfo* slot = PK11_GetInternalSlot(); | 184 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); |
196 SECKEYPublicKey* pubKey = nullptr; | 185 SECKEYPublicKey* pubKeyRaw = nullptr; |
197 SECKEYPrivateKey* privKey = | 186 ScopedSECKEYPrivateKey privKey(PK11_GenerateKeyPair(slot.get(), |
198 PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams, | 187 CKM_RSA_PKCS_KEY_PAIR_GEN, |
199 &pubKey, PR_FALSE, PR_FALSE, nullptr); | 188 &rsaGenParams, &pubKeyRaw, |
189 false, false, nullptr)); | |
190 ASSERT_TRUE(!!privKey && pubKeyRaw); | |
191 ScopedSECKEYPublicKey pubKey(pubKeyRaw); | |
200 | 192 |
201 // Generate random data to sign. | 193 // Generate random data to sign. |
194 uint8_t dataBuf[50]; | |
195 SECItem data = { siBuffer, dataBuf, sizeof(dataBuf) }; | |
202 unsigned int hLen = HASH_ResultLenByOidTag(hashOid); | 196 unsigned int hLen = HASH_ResultLenByOidTag(hashOid); |
203 SECItem* data(SECITEM_AllocItem(nullptr, nullptr, hLen)); | 197 SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), data.data, data.len); |
204 SECStatus rv = PK11_GenerateRandomOnSlot(slot, data->data, data->len); | |
205 EXPECT_EQ(rv, SECSuccess); | 198 EXPECT_EQ(rv, SECSuccess); |
206 | 199 |
207 // Allocate memory for the signature. | 200 // Allocate memory for the signature. |
208 SECItem* sig(SECITEM_AllocItem(nullptr, nullptr, PK11_SignatureLen(privKey))); | 201 std::vector<uint8_t> sigBuf(PK11_SignatureLen(privKey.get())); |
202 SECItem sig = { siBuffer, &sigBuf[0], | |
203 static_cast<unsigned int>(sigBuf.size()) }; | |
209 | 204 |
210 // Set up PSS parameters. | 205 // Set up PSS parameters. |
211 CK_RSA_PKCS_PSS_PARAMS rsaPssParams = { hashMech, mgf, hLen }; | 206 CK_RSA_PKCS_PSS_PARAMS rsaPssParams = { hashMech, mgf, hLen }; |
212 SECItem params = { siBuffer, (unsigned char*)&rsaPssParams, sizeof(rsaPssParam s) }; | 207 SECItem params = { siBuffer, reinterpret_cast<unsigned char*>(&rsaPssParams), |
208 sizeof(rsaPssParams) }; | |
213 | 209 |
214 // Sign. | 210 // Sign. |
215 CK_MECHANISM_TYPE mech = CKM_RSA_PKCS_PSS; | 211 CK_MECHANISM_TYPE mech = CKM_RSA_PKCS_PSS; |
216 rv = PK11_SignWithMechanism(privKey, mech, ¶ms, sig, data); | 212 rv = PK11_SignWithMechanism(privKey.get(), mech, ¶ms, &sig, &data); |
217 EXPECT_EQ(rv, SECSuccess); | 213 EXPECT_EQ(rv, SECSuccess); |
218 | 214 |
219 // Verify. | 215 // Verify. |
220 rv = PK11_VerifyWithMechanism(pubKey, mech, ¶ms, sig, data, nullptr); | 216 rv = PK11_VerifyWithMechanism(pubKey.get(), mech, ¶ms, &sig, &data, |
217 nullptr); | |
221 EXPECT_EQ(rv, SECSuccess); | 218 EXPECT_EQ(rv, SECSuccess); |
222 | 219 |
223 // Cleanup. | 220 // Verification with modified data must fail. |
224 SECKEY_DestroyPrivateKey(privKey); | 221 data.data[0] ^= 0xff; |
225 SECKEY_DestroyPublicKey(pubKey); | 222 rv = PK11_VerifyWithMechanism(pubKey.get(), mech, ¶ms, &sig, &data, |
226 | 223 nullptr); |
227 SECITEM_FreeItem(data, PR_TRUE); | 224 EXPECT_EQ(rv, SECFailure); |
228 SECITEM_FreeItem(sig, PR_TRUE); | 225 |
229 | 226 // Verification with original data but the wrong signature must fail. |
ekr-rietveld
2015/11/06 21:31:58
Please include a test demonstrating that bogus sig
| |
230 PK11_FreeSlot(slot); | 227 data.data[0] ^= 0xff; // Revert previous changes. |
228 sig.data[0] ^= 0xff; | |
229 rv = PK11_VerifyWithMechanism(pubKey.get(), mech, ¶ms, &sig, &data, | |
230 nullptr); | |
231 EXPECT_EQ(rv, SECFailure); | |
231 } | 232 } |
232 | 233 |
233 // RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair | 234 // RSA-PSS test vectors, pss-vect.txt, Example 1.1: A 1024-bit RSA Key Pair |
234 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> | 235 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> |
235 TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature1) { | 236 TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature1) { |
236 TestVector tv = { kTestVector1Spki, sizeof(kTestVector1Spki), | 237 PSS_TEST_VECTOR_VERIFY(kTestVector1Spki, kTestVector1Data, kTestVector1Sig); |
237 kTestVector1Data, sizeof(kTestVector1Data), | |
238 kTestVector1Sig, sizeof(kTestVector1Sig) }; | |
ekr-rietveld
2015/11/06 21:31:59
1. Macros might make this easier.
2. Why bother to
| |
239 Init(&tv); | |
240 Verify(); | |
241 } | 238 } |
242 | 239 |
243 // RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair | 240 // RSA-PSS test vectors, pss-vect.txt, Example 10.1: A 2048-bit RSA Key Pair |
244 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> | 241 // <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip> |
245 TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature2) { | 242 TEST_F(Pkcs11RsaPssVectorTest, VerifyKnownSignature2) { |
246 TestVector tv = { kTestVector2Spki, sizeof(kTestVector2Spki), | 243 PSS_TEST_VECTOR_VERIFY(kTestVector2Spki, kTestVector2Data, kTestVector2Sig); |
247 kTestVector2Data, sizeof(kTestVector2Data), | |
248 kTestVector2Sig, sizeof(kTestVector2Sig) }; | |
249 Init(&tv); | |
250 Verify(); | |
251 } | 244 } |
252 | 245 |
253 } // namespace nss_test | 246 } // namespace nss_test |
254 | 247 |
LEFT | RIGHT |