michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsDataSignatureVerifier.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsString.h" michael@0: michael@0: #include "seccomon.h" michael@0: #include "nssb64.h" michael@0: #include "certt.h" michael@0: #include "keyhi.h" michael@0: #include "cryptohi.h" michael@0: michael@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) michael@0: michael@0: NS_IMPL_ISUPPORTS(nsDataSignatureVerifier, nsIDataSignatureVerifier) michael@0: michael@0: const SEC_ASN1Template CERT_SignatureDataTemplate[] = michael@0: { michael@0: { SEC_ASN1_SEQUENCE, michael@0: 0, nullptr, sizeof(CERTSignedData) }, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, michael@0: offsetof(CERTSignedData,signatureAlgorithm), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), }, michael@0: { SEC_ASN1_BIT_STRING, michael@0: offsetof(CERTSignedData,signature), }, michael@0: { 0, } michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: nsDataSignatureVerifier::VerifyData(const nsACString & aData, michael@0: const nsACString & aSignature, michael@0: const nsACString & aPublicKey, michael@0: bool *_retval) michael@0: { michael@0: // Allocate an arena to handle the majority of the allocations michael@0: PLArenaPool *arena; michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: // Base 64 decode the key michael@0: SECItem keyItem; michael@0: PORT_Memset(&keyItem, 0, sizeof(SECItem)); michael@0: if (!NSSBase64_DecodeBuffer(arena, &keyItem, michael@0: nsPromiseFlatCString(aPublicKey).get(), michael@0: aPublicKey.Length())) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Extract the public key from the data michael@0: CERTSubjectPublicKeyInfo *pki = SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem); michael@0: if (!pki) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(pki); michael@0: SECKEY_DestroySubjectPublicKeyInfo(pki); michael@0: pki = nullptr; michael@0: michael@0: if (!publicKey) { michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Base 64 decode the signature michael@0: SECItem signatureItem; michael@0: PORT_Memset(&signatureItem, 0, sizeof(SECItem)); michael@0: if (!NSSBase64_DecodeBuffer(arena, &signatureItem, michael@0: nsPromiseFlatCString(aSignature).get(), michael@0: aSignature.Length())) { michael@0: SECKEY_DestroyPublicKey(publicKey); michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Decode the signature and algorithm michael@0: CERTSignedData sigData; michael@0: PORT_Memset(&sigData, 0, sizeof(CERTSignedData)); michael@0: SECStatus ss = SEC_QuickDERDecodeItem(arena, &sigData, michael@0: CERT_SignatureDataTemplate, michael@0: &signatureItem); michael@0: if (ss != SECSuccess) { michael@0: SECKEY_DestroyPublicKey(publicKey); michael@0: PORT_FreeArena(arena, false); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Perform the final verification michael@0: DER_ConvertBitString(&(sigData.signature)); michael@0: ss = VFY_VerifyDataWithAlgorithmID((const unsigned char*)nsPromiseFlatCString(aData).get(), michael@0: aData.Length(), publicKey, michael@0: &(sigData.signature), michael@0: &(sigData.signatureAlgorithm), michael@0: nullptr, nullptr); michael@0: michael@0: // Clean up remaining objects michael@0: SECKEY_DestroyPublicKey(publicKey); michael@0: PORT_FreeArena(arena, false); michael@0: michael@0: *_retval = (ss == SECSuccess); michael@0: michael@0: return NS_OK; michael@0: }