nsDataSignatureVerifier.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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/. */
  4. #include "nsDataSignatureVerifier.h"
  5. #include "cms.h"
  6. #include "cryptohi.h"
  7. #include "keyhi.h"
  8. #include "mozilla/Casting.h"
  9. #include "mozilla/Unused.h"
  10. #include "nsCOMPtr.h"
  11. #include "nsNSSComponent.h"
  12. #include "nssb64.h"
  13. #include "pkix/pkixnss.h"
  14. #include "pkix/pkixtypes.h"
  15. #include "ScopedNSSTypes.h"
  16. #include "secerr.h"
  17. #include "SharedCertVerifier.h"
  18. using namespace mozilla;
  19. using namespace mozilla::pkix;
  20. using namespace mozilla::psm;
  21. SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
  22. NS_IMPL_ISUPPORTS(nsDataSignatureVerifier, nsIDataSignatureVerifier)
  23. const SEC_ASN1Template CERT_SignatureDataTemplate[] =
  24. {
  25. { SEC_ASN1_SEQUENCE,
  26. 0, nullptr, sizeof(CERTSignedData) },
  27. { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  28. offsetof(CERTSignedData,signatureAlgorithm),
  29. SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), },
  30. { SEC_ASN1_BIT_STRING,
  31. offsetof(CERTSignedData,signature), },
  32. { 0, }
  33. };
  34. nsDataSignatureVerifier::~nsDataSignatureVerifier()
  35. {
  36. nsNSSShutDownPreventionLock locker;
  37. if (isAlreadyShutDown()) {
  38. return;
  39. }
  40. shutdown(ShutdownCalledFrom::Object);
  41. }
  42. NS_IMETHODIMP
  43. nsDataSignatureVerifier::VerifyData(const nsACString& aData,
  44. const nsACString& aSignature,
  45. const nsACString& aPublicKey,
  46. bool* _retval)
  47. {
  48. NS_ENSURE_ARG_POINTER(_retval);
  49. nsNSSShutDownPreventionLock locker;
  50. if (isAlreadyShutDown()) {
  51. return NS_ERROR_NOT_AVAILABLE;
  52. }
  53. // Allocate an arena to handle the majority of the allocations
  54. UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  55. if (!arena) {
  56. return NS_ERROR_OUT_OF_MEMORY;
  57. }
  58. // Base 64 decode the key
  59. SECItem keyItem;
  60. PORT_Memset(&keyItem, 0, sizeof(SECItem));
  61. if (!NSSBase64_DecodeBuffer(arena.get(), &keyItem,
  62. PromiseFlatCString(aPublicKey).get(),
  63. aPublicKey.Length())) {
  64. return NS_ERROR_FAILURE;
  65. }
  66. // Extract the public key from the data
  67. UniqueCERTSubjectPublicKeyInfo pki(
  68. SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem));
  69. if (!pki) {
  70. return NS_ERROR_FAILURE;
  71. }
  72. UniqueSECKEYPublicKey publicKey(SECKEY_ExtractPublicKey(pki.get()));
  73. if (!publicKey) {
  74. return NS_ERROR_FAILURE;
  75. }
  76. // Base 64 decode the signature
  77. SECItem signatureItem;
  78. PORT_Memset(&signatureItem, 0, sizeof(SECItem));
  79. if (!NSSBase64_DecodeBuffer(arena.get(), &signatureItem,
  80. PromiseFlatCString(aSignature).get(),
  81. aSignature.Length())) {
  82. return NS_ERROR_FAILURE;
  83. }
  84. // Decode the signature and algorithm
  85. CERTSignedData sigData;
  86. PORT_Memset(&sigData, 0, sizeof(CERTSignedData));
  87. SECStatus srv = SEC_QuickDERDecodeItem(arena.get(), &sigData,
  88. CERT_SignatureDataTemplate,
  89. &signatureItem);
  90. if (srv != SECSuccess) {
  91. return NS_ERROR_FAILURE;
  92. }
  93. // Perform the final verification
  94. DER_ConvertBitString(&(sigData.signature));
  95. srv = VFY_VerifyDataWithAlgorithmID(
  96. BitwiseCast<const unsigned char*, const char*>(
  97. PromiseFlatCString(aData).get()),
  98. aData.Length(), publicKey.get(), &(sigData.signature),
  99. &(sigData.signatureAlgorithm), nullptr, nullptr);
  100. *_retval = (srv == SECSuccess);
  101. return NS_OK;
  102. }
  103. namespace mozilla {
  104. nsresult
  105. VerifyCMSDetachedSignatureIncludingCertificate(
  106. const SECItem& buffer, const SECItem& detachedDigest,
  107. nsresult (*verifyCertificate)(CERTCertificate* cert, void* context,
  108. void* pinArg),
  109. void* verifyCertificateContext, void* pinArg,
  110. const nsNSSShutDownPreventionLock& /*proofOfLock*/)
  111. {
  112. // XXX: missing pinArg is tolerated.
  113. if (NS_WARN_IF(!buffer.data && buffer.len > 0) ||
  114. NS_WARN_IF(!detachedDigest.data && detachedDigest.len > 0) ||
  115. (!verifyCertificate) ||
  116. NS_WARN_IF(!verifyCertificateContext)) {
  117. return NS_ERROR_INVALID_ARG;
  118. }
  119. UniqueNSSCMSMessage
  120. cmsMsg(NSS_CMSMessage_CreateFromDER(const_cast<SECItem*>(&buffer), nullptr,
  121. nullptr, nullptr, nullptr, nullptr,
  122. nullptr));
  123. if (!cmsMsg) {
  124. return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
  125. }
  126. if (!NSS_CMSMessage_IsSigned(cmsMsg.get())) {
  127. return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
  128. }
  129. NSSCMSContentInfo* cinfo = NSS_CMSMessage_ContentLevel(cmsMsg.get(), 0);
  130. if (!cinfo) {
  131. return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
  132. }
  133. // We're expecting this to be a PKCS#7 signedData content info.
  134. if (NSS_CMSContentInfo_GetContentTypeTag(cinfo)
  135. != SEC_OID_PKCS7_SIGNED_DATA) {
  136. return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
  137. }
  138. // signedData is non-owning
  139. NSSCMSSignedData* signedData =
  140. static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(cinfo));
  141. if (!signedData) {
  142. return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
  143. }
  144. // Set digest value.
  145. if (NSS_CMSSignedData_SetDigestValue(signedData, SEC_OID_SHA1,
  146. const_cast<SECItem*>(&detachedDigest))) {
  147. return NS_ERROR_CMS_VERIFY_BAD_DIGEST;
  148. }
  149. // Parse the certificates into CERTCertificate objects held in memory so
  150. // verifyCertificate will be able to find them during path building.
  151. UniqueCERTCertList certs(CERT_NewCertList());
  152. if (!certs) {
  153. return NS_ERROR_OUT_OF_MEMORY;
  154. }
  155. if (signedData->rawCerts) {
  156. for (size_t i = 0; signedData->rawCerts[i]; ++i) {
  157. UniqueCERTCertificate
  158. cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  159. signedData->rawCerts[i], nullptr, false,
  160. true));
  161. // Skip certificates that fail to parse
  162. if (!cert) {
  163. continue;
  164. }
  165. if (CERT_AddCertToListTail(certs.get(), cert.get()) != SECSuccess) {
  166. return NS_ERROR_OUT_OF_MEMORY;
  167. }
  168. Unused << cert.release(); // Ownership transferred to the cert list.
  169. }
  170. }
  171. // Get the end-entity certificate.
  172. int numSigners = NSS_CMSSignedData_SignerInfoCount(signedData);
  173. if (NS_WARN_IF(numSigners != 1)) {
  174. return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
  175. }
  176. // signer is non-owning.
  177. NSSCMSSignerInfo* signer = NSS_CMSSignedData_GetSignerInfo(signedData, 0);
  178. if (NS_WARN_IF(!signer)) {
  179. return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
  180. }
  181. CERTCertificate* signerCert =
  182. NSS_CMSSignerInfo_GetSigningCertificate(signer, CERT_GetDefaultCertDB());
  183. if (!signerCert) {
  184. return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
  185. }
  186. nsresult rv = verifyCertificate(signerCert, verifyCertificateContext, pinArg);
  187. if (NS_WARN_IF(NS_FAILED(rv))) {
  188. return rv;
  189. }
  190. // See NSS_CMSContentInfo_GetContentTypeOID, which isn't exported from NSS.
  191. SECOidData* contentTypeOidData =
  192. SECOID_FindOID(&signedData->contentInfo.contentType);
  193. if (!contentTypeOidData) {
  194. return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
  195. }
  196. return MapSECStatus(NSS_CMSSignerInfo_Verify(signer,
  197. const_cast<SECItem*>(&detachedDigest),
  198. &contentTypeOidData->oid));
  199. }
  200. } // namespace mozilla
  201. namespace {
  202. struct VerifyCertificateContext
  203. {
  204. nsCOMPtr<nsIX509Cert> signingCert;
  205. UniqueCERTCertList builtChain;
  206. };
  207. static nsresult
  208. VerifyCertificate(CERTCertificate* cert, void* voidContext, void* pinArg)
  209. {
  210. // XXX: missing pinArg is tolerated
  211. if (NS_WARN_IF(!cert) || NS_WARN_IF(!voidContext)) {
  212. return NS_ERROR_INVALID_ARG;
  213. }
  214. VerifyCertificateContext* context =
  215. static_cast<VerifyCertificateContext*>(voidContext);
  216. nsCOMPtr<nsIX509Cert> xpcomCert(nsNSSCertificate::Create(cert));
  217. if (!xpcomCert) {
  218. return NS_ERROR_OUT_OF_MEMORY;
  219. }
  220. context->signingCert = xpcomCert;
  221. RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
  222. NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
  223. mozilla::pkix::Result result =
  224. certVerifier->VerifyCert(cert,
  225. certificateUsageObjectSigner,
  226. Now(), pinArg,
  227. nullptr, // hostname
  228. context->builtChain);
  229. if (result != Success) {
  230. return GetXPCOMFromNSSError(MapResultToPRErrorCode(result));
  231. }
  232. return NS_OK;
  233. }
  234. } // namespace
  235. NS_IMETHODIMP
  236. nsDataSignatureVerifier::VerifySignature(const char* aRSABuf,
  237. uint32_t aRSABufLen,
  238. const char* aPlaintext,
  239. uint32_t aPlaintextLen,
  240. int32_t* aErrorCode,
  241. nsIX509Cert** aSigningCert)
  242. {
  243. if (!aRSABuf || !aPlaintext || !aErrorCode || !aSigningCert) {
  244. return NS_ERROR_INVALID_ARG;
  245. }
  246. nsNSSShutDownPreventionLock locker;
  247. if (isAlreadyShutDown()) {
  248. return NS_ERROR_NOT_AVAILABLE;
  249. }
  250. *aErrorCode = VERIFY_ERROR_OTHER;
  251. *aSigningCert = nullptr;
  252. Digest digest;
  253. nsresult rv = digest.DigestBuf(
  254. SEC_OID_SHA1,
  255. BitwiseCast<const uint8_t*, const char*>(aPlaintext),
  256. aPlaintextLen);
  257. if (NS_WARN_IF(NS_FAILED(rv))) {
  258. return rv;
  259. }
  260. SECItem buffer = {
  261. siBuffer,
  262. BitwiseCast<unsigned char*, const char*>(aRSABuf),
  263. aRSABufLen
  264. };
  265. VerifyCertificateContext context;
  266. // XXX: pinArg is missing
  267. rv = VerifyCMSDetachedSignatureIncludingCertificate(buffer, digest.get(),
  268. VerifyCertificate,
  269. &context, nullptr, locker);
  270. if (NS_SUCCEEDED(rv)) {
  271. *aErrorCode = VERIFY_OK;
  272. } else if (NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_SECURITY) {
  273. if (rv == GetXPCOMFromNSSError(SEC_ERROR_UNKNOWN_ISSUER)) {
  274. *aErrorCode = VERIFY_ERROR_UNKNOWN_ISSUER;
  275. } else {
  276. *aErrorCode = VERIFY_ERROR_OTHER;
  277. }
  278. rv = NS_OK;
  279. }
  280. if (rv == NS_OK) {
  281. context.signingCert.forget(aSigningCert);
  282. }
  283. return rv;
  284. }