Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsDataSignatureVerifier.h"
6 #include "nsCOMPtr.h"
7 #include "nsString.h"
9 #include "seccomon.h"
10 #include "nssb64.h"
11 #include "certt.h"
12 #include "keyhi.h"
13 #include "cryptohi.h"
15 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
17 NS_IMPL_ISUPPORTS(nsDataSignatureVerifier, nsIDataSignatureVerifier)
19 const SEC_ASN1Template CERT_SignatureDataTemplate[] =
20 {
21 { SEC_ASN1_SEQUENCE,
22 0, nullptr, sizeof(CERTSignedData) },
23 { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
24 offsetof(CERTSignedData,signatureAlgorithm),
25 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), },
26 { SEC_ASN1_BIT_STRING,
27 offsetof(CERTSignedData,signature), },
28 { 0, }
29 };
31 NS_IMETHODIMP
32 nsDataSignatureVerifier::VerifyData(const nsACString & aData,
33 const nsACString & aSignature,
34 const nsACString & aPublicKey,
35 bool *_retval)
36 {
37 // Allocate an arena to handle the majority of the allocations
38 PLArenaPool *arena;
39 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
40 if (!arena)
41 return NS_ERROR_OUT_OF_MEMORY;
43 // Base 64 decode the key
44 SECItem keyItem;
45 PORT_Memset(&keyItem, 0, sizeof(SECItem));
46 if (!NSSBase64_DecodeBuffer(arena, &keyItem,
47 nsPromiseFlatCString(aPublicKey).get(),
48 aPublicKey.Length())) {
49 PORT_FreeArena(arena, false);
50 return NS_ERROR_FAILURE;
51 }
53 // Extract the public key from the data
54 CERTSubjectPublicKeyInfo *pki = SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem);
55 if (!pki) {
56 PORT_FreeArena(arena, false);
57 return NS_ERROR_FAILURE;
58 }
59 SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(pki);
60 SECKEY_DestroySubjectPublicKeyInfo(pki);
61 pki = nullptr;
63 if (!publicKey) {
64 PORT_FreeArena(arena, false);
65 return NS_ERROR_FAILURE;
66 }
68 // Base 64 decode the signature
69 SECItem signatureItem;
70 PORT_Memset(&signatureItem, 0, sizeof(SECItem));
71 if (!NSSBase64_DecodeBuffer(arena, &signatureItem,
72 nsPromiseFlatCString(aSignature).get(),
73 aSignature.Length())) {
74 SECKEY_DestroyPublicKey(publicKey);
75 PORT_FreeArena(arena, false);
76 return NS_ERROR_FAILURE;
77 }
79 // Decode the signature and algorithm
80 CERTSignedData sigData;
81 PORT_Memset(&sigData, 0, sizeof(CERTSignedData));
82 SECStatus ss = SEC_QuickDERDecodeItem(arena, &sigData,
83 CERT_SignatureDataTemplate,
84 &signatureItem);
85 if (ss != SECSuccess) {
86 SECKEY_DestroyPublicKey(publicKey);
87 PORT_FreeArena(arena, false);
88 return NS_ERROR_FAILURE;
89 }
91 // Perform the final verification
92 DER_ConvertBitString(&(sigData.signature));
93 ss = VFY_VerifyDataWithAlgorithmID((const unsigned char*)nsPromiseFlatCString(aData).get(),
94 aData.Length(), publicKey,
95 &(sigData.signature),
96 &(sigData.signatureAlgorithm),
97 nullptr, nullptr);
99 // Clean up remaining objects
100 SECKEY_DestroyPublicKey(publicKey);
101 PORT_FreeArena(arena, false);
103 *_retval = (ss == SECSuccess);
105 return NS_OK;
106 }