686 lines
20 KiB
C++
686 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsNSSCertificate.h"
|
|
|
|
#include "CertVerifier.h"
|
|
#include "ExtendedValidation.h"
|
|
#include "NSSCertDBTrustDomain.h"
|
|
#include "X509CertValidity.h"
|
|
#include "certdb.h"
|
|
#include "ipc/IPCMessageUtils.h"
|
|
#include "mozilla/Assertions.h"
|
|
#include "mozilla/Base64.h"
|
|
#include "mozilla/Casting.h"
|
|
#include "mozilla/NotNull.h"
|
|
#include "mozilla/Span.h"
|
|
#include "mozilla/TextUtils.h"
|
|
#include "mozilla/Unused.h"
|
|
#include "mozilla/ipc/TransportSecurityInfoUtils.h"
|
|
#include "mozilla/ipc/IPDLParamTraits.h"
|
|
#include "mozilla/net/DNS.h"
|
|
#include "mozpkix/Result.h"
|
|
#include "mozpkix/pkixnss.h"
|
|
#include "mozpkix/pkixtypes.h"
|
|
#include "mozpkix/pkixutil.h"
|
|
#include "nsArray.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIClassInfoImpl.h"
|
|
#include "nsIObjectInputStream.h"
|
|
#include "nsIObjectOutputStream.h"
|
|
#include "nsIX509Cert.h"
|
|
#include "nsNSSCertHelper.h"
|
|
#include "nsNSSCertTrust.h"
|
|
#include "nsPK11TokenDB.h"
|
|
#include "nsPKCS12Blob.h"
|
|
#include "nsProxyRelease.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsString.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsUnicharUtils.h"
|
|
#include "nspr.h"
|
|
#include "prerror.h"
|
|
#include "secasn1.h"
|
|
#include "secder.h"
|
|
#include "secerr.h"
|
|
#include "ssl.h"
|
|
|
|
#ifdef XP_WIN
|
|
# include <winsock.h> // for htonl
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::psm;
|
|
|
|
extern LazyLogModule gPIPNSSLog;
|
|
|
|
NS_IMPL_ISUPPORTS(nsNSSCertificate, nsIX509Cert, nsISerializable, nsIClassInfo)
|
|
|
|
nsNSSCertificate::nsNSSCertificate() : mCert("nsNSSCertificate::mCert") {}
|
|
|
|
nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
|
|
: mCert("nsNSSCertificate::mCert") {
|
|
if (cert) {
|
|
mDER.AppendElements(cert->derCert.data, cert->derCert.len);
|
|
auto lock = mCert.Lock();
|
|
auto& maybeCert = lock.ref();
|
|
maybeCert.emplace(UniqueCERTCertificate(CERT_DupCertificate(cert)));
|
|
}
|
|
}
|
|
|
|
nsNSSCertificate::nsNSSCertificate(nsTArray<uint8_t>&& der)
|
|
: mDER(std::move(der)), mCert("nsNSSCertificate::mCert") {}
|
|
|
|
UniqueCERTCertificate nsNSSCertificate::GetOrInstantiateCert() {
|
|
auto lock = mCert.Lock();
|
|
auto& maybeCert = lock.ref();
|
|
if (maybeCert.isSome()) {
|
|
return UniqueCERTCertificate(CERT_DupCertificate((*maybeCert).get()));
|
|
}
|
|
|
|
if (!EnsureNSSInitializedChromeOrContent()) {
|
|
return nullptr;
|
|
}
|
|
|
|
SECItem derItem = {siBuffer, mDER.Elements(),
|
|
static_cast<unsigned int>(mDER.Length())};
|
|
UniqueCERTCertificate cert(CERT_NewTempCertificate(
|
|
CERT_GetDefaultCertDB(), &derItem, nullptr, false, true));
|
|
if (!cert) {
|
|
return nullptr;
|
|
}
|
|
maybeCert.emplace(std::move(cert));
|
|
|
|
return UniqueCERTCertificate(CERT_DupCertificate((*maybeCert).get()));
|
|
}
|
|
|
|
nsresult nsNSSCertificate::GetCertType(uint32_t* aCertType) {
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
CERTCertTrust certTrust{0, 0, 0};
|
|
// If there is no stored trust information, CERT_GetCertTrust will return
|
|
// SECFailure. This isn't a failure. In this case, all trust bits will remain
|
|
// unset.
|
|
Unused << CERT_GetCertTrust(cert.get(), &certTrust);
|
|
nsNSSCertTrust trust(&certTrust);
|
|
if (cert->nickname && trust.HasAnyUser()) {
|
|
*aCertType = nsIX509Cert::USER_CERT;
|
|
return NS_OK;
|
|
}
|
|
if (trust.HasAnyCA()) {
|
|
*aCertType = nsIX509Cert::CA_CERT;
|
|
return NS_OK;
|
|
}
|
|
if (trust.HasPeer(true, false)) {
|
|
*aCertType = nsIX509Cert::SERVER_CERT;
|
|
return NS_OK;
|
|
}
|
|
if (trust.HasPeer(false, true) && cert->emailAddr) {
|
|
*aCertType = nsIX509Cert::EMAIL_CERT;
|
|
return NS_OK;
|
|
}
|
|
if (CERT_IsCACert(cert.get(), nullptr)) {
|
|
*aCertType = nsIX509Cert::CA_CERT;
|
|
return NS_OK;
|
|
}
|
|
if (cert->emailAddr) {
|
|
*aCertType = nsIX509Cert::EMAIL_CERT;
|
|
return NS_OK;
|
|
}
|
|
*aCertType = nsIX509Cert::UNKNOWN_CERT;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetDbKey(nsACString& aDbKey) {
|
|
static_assert(sizeof(uint64_t) == 8, "type size consistency check");
|
|
static_assert(sizeof(uint32_t) == 4, "type size consistency check");
|
|
|
|
pkix::Input certInput;
|
|
pkix::Result result = certInput.Init(mDER.Elements(), mDER.Length());
|
|
if (result != pkix::Result::Success) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
// NB: since we're not building a trust path, the endEntityOrCA parameter is
|
|
// irrelevant.
|
|
pkix::BackCert cert(certInput, pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
|
|
result = cert.Init();
|
|
if (result != pkix::Result::Success) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
// The format of the key is the base64 encoding of the following:
|
|
// 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
|
|
// never implemented)
|
|
// 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
|
|
// never implemented)
|
|
// 4 bytes: <serial number length in big-endian order>
|
|
// 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
|
|
// n bytes: <bytes of serial number>
|
|
// m bytes: <DER-encoded issuer distinguished name>
|
|
nsAutoCString buf;
|
|
const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
buf.Append(leadingZeroes, sizeof(leadingZeroes));
|
|
uint32_t serialNumberLen = htonl(cert.GetSerialNumber().GetLength());
|
|
buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
|
|
sizeof(uint32_t));
|
|
uint32_t issuerLen = htonl(cert.GetIssuer().GetLength());
|
|
buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
|
|
sizeof(uint32_t));
|
|
buf.Append(BitwiseCast<const char*, const unsigned char*>(
|
|
cert.GetSerialNumber().UnsafeGetData()),
|
|
cert.GetSerialNumber().GetLength());
|
|
buf.Append(BitwiseCast<const char*, const unsigned char*>(
|
|
cert.GetIssuer().UnsafeGetData()),
|
|
cert.GetIssuer().GetLength());
|
|
|
|
return Base64Encode(buf, aDbKey);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetDisplayName(nsAString& aDisplayName) {
|
|
aDisplayName.Truncate();
|
|
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
UniquePORTString commonName(CERT_GetCommonName(&cert->subject));
|
|
UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&cert->subject));
|
|
UniquePORTString organizationName(CERT_GetOrgName(&cert->subject));
|
|
|
|
// Only use the nickname for built-in roots where we already have a hard-coded
|
|
// reasonable display name (unfortunately we have to strip off the leading
|
|
// slot identifier followed by a ':'). Otherwise, attempt to use the following
|
|
// in order:
|
|
// - the common name, if present
|
|
// - an organizational unit name, if present
|
|
// - an organization name, if present
|
|
// - the entire subject distinguished name, if non-empty
|
|
// - an email address, if one can be found
|
|
// In the unlikely event that none of these fields are present and non-empty
|
|
// (the subject really shouldn't be empty), an empty string is returned.
|
|
nsAutoCString builtInRootNickname;
|
|
nsAutoCString fullNickname(cert->nickname);
|
|
static const nsLiteralCString kBuiltinObjectTokenPrefix =
|
|
"Builtin Object Token:"_ns;
|
|
if (StringBeginsWith(fullNickname, kBuiltinObjectTokenPrefix)) {
|
|
// Substring will gracefully handle the case where index is the last
|
|
// character in the string (that is, if the nickname is just
|
|
// "Builtin Object Token:"). In that case, we'll get an empty string.
|
|
builtInRootNickname =
|
|
Substring(fullNickname, kBuiltinObjectTokenPrefix.Length());
|
|
}
|
|
const char* nameOptions[] = {builtInRootNickname.get(),
|
|
commonName.get(),
|
|
organizationalUnitName.get(),
|
|
organizationName.get(),
|
|
cert->subjectName,
|
|
cert->emailAddr};
|
|
|
|
for (auto nameOption : nameOptions) {
|
|
if (nameOption) {
|
|
size_t len = strlen(nameOption);
|
|
if (len > 0) {
|
|
LossyUTF8ToUTF16(nameOption, len, aDisplayName);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress) {
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (cert->emailAddr) {
|
|
CopyUTF8toUTF16(MakeStringSpan(cert->emailAddr), aEmailAddress);
|
|
} else {
|
|
GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetEmailAddresses(nsTArray<nsString>& aAddresses) {
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
uint32_t length = 0;
|
|
for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
|
|
aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
|
|
++(length);
|
|
}
|
|
|
|
aAddresses.SetCapacity(length);
|
|
|
|
for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
|
|
aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
|
|
CopyASCIItoUTF16(MakeStringSpan(aAddr), *aAddresses.AppendElement());
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
|
|
bool* result) {
|
|
NS_ENSURE_ARG(result);
|
|
*result = false;
|
|
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
for (const char* aAddr = CERT_GetFirstEmailAddress(cert.get()); aAddr;
|
|
aAddr = CERT_GetNextEmailAddress(cert.get(), aAddr)) {
|
|
nsAutoString certAddr;
|
|
LossyUTF8ToUTF16(aAddr, strlen(aAddr), certAddr);
|
|
ToLowerCase(certAddr);
|
|
|
|
nsAutoString testAddr(aEmailAddress);
|
|
ToLowerCase(testAddr);
|
|
|
|
if (certAddr == testAddr) {
|
|
*result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetCommonName(nsAString& aCommonName) {
|
|
aCommonName.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString commonName(CERT_GetCommonName(&cert->subject));
|
|
if (commonName) {
|
|
LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetOrganization(nsAString& aOrganization) {
|
|
aOrganization.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString organization(CERT_GetOrgName(&cert->subject));
|
|
if (organization) {
|
|
LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
|
|
aOrganization);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName) {
|
|
aCommonName.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString commonName(CERT_GetCommonName(&cert->issuer));
|
|
if (commonName) {
|
|
LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization) {
|
|
aOrganization.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString organization(CERT_GetOrgName(&cert->issuer));
|
|
if (organization) {
|
|
LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
|
|
aOrganization);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit) {
|
|
aOrganizationUnit.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString organizationUnit(CERT_GetOrgUnitName(&cert->issuer));
|
|
if (organizationUnit) {
|
|
LossyUTF8ToUTF16(organizationUnit.get(), strlen(organizationUnit.get()),
|
|
aOrganizationUnit);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit) {
|
|
aOrganizationalUnit.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString orgunit(CERT_GetOrgUnitName(&cert->subject));
|
|
if (orgunit) {
|
|
LossyUTF8ToUTF16(orgunit.get(), strlen(orgunit.get()), aOrganizationalUnit);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSubjectName(nsAString& _subjectName) {
|
|
_subjectName.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (cert->subjectName) {
|
|
LossyUTF8ToUTF16(cert->subjectName, strlen(cert->subjectName),
|
|
_subjectName);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerName(nsAString& _issuerName) {
|
|
_issuerName.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (cert->issuerName) {
|
|
LossyUTF8ToUTF16(cert->issuerName, strlen(cert->issuerName), _issuerName);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber) {
|
|
_serialNumber.Truncate();
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePORTString tmpstr(
|
|
CERT_Hexify(&cert->serialNumber, true /* use colon delimiters */));
|
|
if (tmpstr) {
|
|
_serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint,
|
|
SECOidTag aHashAlg) {
|
|
aFingerprint.Truncate();
|
|
|
|
if (!EnsureNSSInitializedChromeOrContent()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
nsTArray<uint8_t> digestArray;
|
|
nsresult rv =
|
|
Digest::DigestBuf(aHashAlg, mDER.Elements(), mDER.Length(), digestArray);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
SECItem digestItem = {siBuffer, digestArray.Elements(),
|
|
static_cast<unsigned int>(digestArray.Length())};
|
|
|
|
UniquePORTString fpStr(
|
|
CERT_Hexify(&digestItem, true /* use colon delimiters */));
|
|
if (!fpStr) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
aFingerprint.AssignASCII(fpStr.get());
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint) {
|
|
return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint) {
|
|
return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetTokenName(nsAString& aTokenName) {
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
if (!cert) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
UniquePK11SlotInfo internalSlot(PK11_GetInternalSlot());
|
|
if (!internalSlot) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsCOMPtr<nsIPK11Token> token(
|
|
new nsPK11Token(cert->slot ? cert->slot : internalSlot.get()));
|
|
nsAutoCString tmp;
|
|
nsresult rv = token->GetTokenName(tmp);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
aTokenName.Assign(NS_ConvertUTF8toUTF16(tmp));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(
|
|
nsACString& aSha256SPKIDigest) {
|
|
aSha256SPKIDigest.Truncate();
|
|
|
|
if (!EnsureNSSInitializedChromeOrContent()) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
pkix::Input certInput;
|
|
pkix::Result result = certInput.Init(mDER.Elements(), mDER.Length());
|
|
if (result != pkix::Result::Success) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
// NB: since we're not building a trust path, the endEntityOrCA parameter is
|
|
// irrelevant.
|
|
pkix::BackCert cert(certInput, pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
|
|
result = cert.Init();
|
|
if (result != pkix::Result::Success) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
pkix::Input derPublicKey = cert.GetSubjectPublicKeyInfo();
|
|
nsTArray<uint8_t> digestArray;
|
|
nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
|
|
derPublicKey.GetLength(), digestArray);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
rv = Base64Encode(nsDependentCSubstring(
|
|
reinterpret_cast<const char*>(digestArray.Elements()),
|
|
digestArray.Length()),
|
|
aSha256SPKIDigest);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetRawDER(nsTArray<uint8_t>& aArray) {
|
|
aArray.SetLength(mDER.Length());
|
|
memcpy(aArray.Elements(), mDER.Elements(), mDER.Length());
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetBase64DERString(nsACString& base64DERString) {
|
|
nsDependentCSubstring derString(
|
|
reinterpret_cast<const char*>(mDER.Elements()), mDER.Length());
|
|
nsresult rv = Base64Encode(derString, base64DERString);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
CERTCertificate* nsNSSCertificate::GetCert() {
|
|
UniqueCERTCertificate cert(GetOrInstantiateCert());
|
|
return cert.release(); // caller takes ownership
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity) {
|
|
NS_ENSURE_ARG(aValidity);
|
|
pkix::Input certInput;
|
|
pkix::Result rv = certInput.Init(mDER.Elements(), mDER.Length());
|
|
if (rv != pkix::Success) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsCOMPtr<nsIX509CertValidity> validity = new X509CertValidity(certInput);
|
|
validity.forget(aValidity);
|
|
return NS_OK;
|
|
}
|
|
|
|
// NB: Any updates (except disk-only fields) must be kept in sync with
|
|
// |SerializeToIPC|.
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::Write(nsIObjectOutputStream* aStream) {
|
|
// This field used to be the cached EV status, but it is no longer necessary.
|
|
nsresult rv = aStream->Write32(0);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
rv = aStream->Write32(mDER.Length());
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
return aStream->WriteBytes(Span(mDER));
|
|
}
|
|
|
|
// NB: Any updates (except disk-only fields) must be kept in sync with
|
|
// |DeserializeFromIPC|.
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::Read(nsIObjectInputStream* aStream) {
|
|
auto lock = mCert.Lock();
|
|
auto& maybeCert = lock.ref();
|
|
if (!mDER.IsEmpty() || maybeCert.isSome()) {
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
}
|
|
|
|
// This field is no longer used.
|
|
uint32_t unusedCachedEVStatus;
|
|
nsresult rv = aStream->Read32(&unusedCachedEVStatus);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
uint32_t len;
|
|
rv = aStream->Read32(&len);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
rv = aStream->ReadByteArray(len, mDER);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsNSSCertificate::SerializeToIPC(IPC::MessageWriter* aWriter) {
|
|
bool hasCert = !mDER.IsEmpty();
|
|
WriteParam(aWriter, hasCert);
|
|
|
|
if (!hasCert) {
|
|
return;
|
|
}
|
|
|
|
WriteParam(aWriter, mDER);
|
|
}
|
|
|
|
bool nsNSSCertificate::DeserializeFromIPC(IPC::MessageReader* aReader) {
|
|
auto lock = mCert.Lock();
|
|
auto& maybeCert = lock.ref();
|
|
if (!mDER.IsEmpty() || maybeCert.isSome()) {
|
|
return false;
|
|
}
|
|
|
|
bool hasCert = false;
|
|
if (!ReadParam(aReader, &hasCert)) {
|
|
return false;
|
|
}
|
|
|
|
if (!hasCert) {
|
|
return true;
|
|
}
|
|
|
|
if (!ReadParam(aReader, &mDER)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetInterfaces(nsTArray<nsIID>& array) {
|
|
array.Clear();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval) {
|
|
*_retval = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetContractID(nsACString& aContractID) {
|
|
aContractID.SetIsVoid(true);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassDescription(nsACString& aClassDescription) {
|
|
aClassDescription.SetIsVoid(true);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassID(nsCID** aClassID) {
|
|
*aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
|
|
return GetClassIDNoAlloc(*aClassID);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetFlags(uint32_t* aFlags) {
|
|
*aFlags = nsIClassInfo::THREADSAFE;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
|
|
static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
|
|
|
|
*aClassIDNoAlloc = kNSSCertificateCID;
|
|
return NS_OK;
|
|
}
|