зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1012549 - 0001. Support import PKCS12 certificate. r=dkeeler r=vchang
This commit is contained in:
Родитель
c4ff04039a
Коммит
ce50eac5c5
|
@ -589,6 +589,7 @@ SEC_PKCS12DecoderFinish
|
|||
SEC_PKCS12DecoderImportBags
|
||||
SEC_PKCS12DecoderIterateInit
|
||||
SEC_PKCS12DecoderIterateNext
|
||||
SEC_PKCS12DecoderRenameCertNicknames
|
||||
SEC_PKCS12DecoderStart
|
||||
SEC_PKCS12DecoderUpdate
|
||||
SEC_PKCS12DecoderValidateBags
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "WifiCertService.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
@ -71,9 +72,14 @@ private:
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Only support DER format now.
|
||||
return ImportDERBlob(buf, size, mResult.mNickname,
|
||||
&mResult.mUsageFlag);
|
||||
// Try import as DER format first.
|
||||
rv = ImportDERBlob(buf, size);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Try import as PKCS#12 format.
|
||||
return ImportPKCS12Blob(buf, size, mPassword);
|
||||
}
|
||||
|
||||
virtual void CallCallback(nsresult rv)
|
||||
|
@ -84,20 +90,148 @@ private:
|
|||
gWifiCertService->DispatchResult(mResult);
|
||||
}
|
||||
|
||||
nsresult ImportDERBlob(char* buf, uint32_t size,
|
||||
const nsAString& aNickname,
|
||||
/*out*/ uint16_t* aUsageFlag)
|
||||
nsresult ImportDERBlob(char* buf, uint32_t size)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aUsageFlag);
|
||||
|
||||
// Create certificate object.
|
||||
ScopedCERTCertificate cert(CERT_DecodeCertFromPackage(buf, size));
|
||||
if (!cert) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
// Import certificate with nickname.
|
||||
return ImportCert(cert, aNickname, aUsageFlag);
|
||||
// Import certificate.
|
||||
return ImportCert(cert);
|
||||
}
|
||||
|
||||
static SECItem*
|
||||
HandleNicknameCollision(SECItem* aOldNickname, PRBool* aCancel, void* aWincx)
|
||||
{
|
||||
const char* dummyName = "Imported User Cert";
|
||||
const size_t dummyNameLen = strlen(dummyName);
|
||||
SECItem* newNick = ::SECITEM_AllocItem(nullptr, nullptr, dummyNameLen + 1);
|
||||
if (!newNick) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
newNick->type = siAsciiString;
|
||||
// Dummy name, will be renamed later.
|
||||
memcpy(newNick->data, dummyName, dummyNameLen + 1);
|
||||
newNick->len = dummyNameLen;
|
||||
|
||||
return newNick;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
HandleNicknameUpdate(const CERTCertificate *aCert,
|
||||
const SECItem *default_nickname,
|
||||
SECItem **new_nickname,
|
||||
void *arg)
|
||||
{
|
||||
WifiCertServiceResultOptions *result = (WifiCertServiceResultOptions *)arg;
|
||||
|
||||
nsCString userNickname;
|
||||
CopyUTF16toUTF8(result->mNickname, userNickname);
|
||||
|
||||
nsCString fullNickname;
|
||||
if (aCert->isRoot && (aCert->nsCertType & NS_CERT_TYPE_SSL_CA)) {
|
||||
// Accept self-signed SSL CA as server certificate.
|
||||
fullNickname.AssignLiteral("WIFI_SERVERCERT_");
|
||||
fullNickname += userNickname;
|
||||
result->mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER;
|
||||
} else if (aCert->nsCertType & NS_CERT_TYPE_SSL_CLIENT) {
|
||||
// User Certificate
|
||||
fullNickname.AssignLiteral("WIFI_USERCERT_");
|
||||
fullNickname += userNickname;
|
||||
result->mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER;
|
||||
}
|
||||
char* nickname;
|
||||
uint32_t length = fullNickname.GetMutableData(&nickname);
|
||||
|
||||
SECItem* newNick = ::SECITEM_AllocItem(nullptr, nullptr, length + 1);
|
||||
if (!newNick) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
newNick->type = siAsciiString;
|
||||
memcpy(newNick->data, nickname, length + 1);
|
||||
newNick->len = length;
|
||||
|
||||
*new_nickname = newNick;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
nsresult ImportPKCS12Blob(char* buf, uint32_t size, const nsAString& aPassword)
|
||||
{
|
||||
nsString password(aPassword);
|
||||
|
||||
// password is null-terminated wide-char string.
|
||||
// passwordItem is required to be big-endian form of password, stored in char
|
||||
// array, including the null-termination.
|
||||
uint32_t length = password.Length() + 1;
|
||||
ScopedSECItem passwordItem(
|
||||
::SECITEM_AllocItem(nullptr, nullptr, length * sizeof(nsString::char_type)));
|
||||
|
||||
if (!passwordItem) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mozilla::NativeEndian::copyAndSwapToBigEndian(passwordItem->data,
|
||||
password.BeginReading(),
|
||||
length);
|
||||
// Create a decoder.
|
||||
ScopedSEC_PKCS12DecoderContext p12dcx(SEC_PKCS12DecoderStart(
|
||||
passwordItem, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr));
|
||||
|
||||
if (!p12dcx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Assign data to decorder.
|
||||
SECStatus srv = SEC_PKCS12DecoderUpdate(p12dcx,
|
||||
reinterpret_cast<unsigned char*>(buf),
|
||||
size);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
// Verify certificates.
|
||||
srv = SEC_PKCS12DecoderVerify(p12dcx);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
// Set certificate nickname and usage flag.
|
||||
srv = SEC_PKCS12DecoderRenameCertNicknames(p12dcx, HandleNicknameUpdate,
|
||||
&mResult);
|
||||
|
||||
// Validate certificates.
|
||||
srv = SEC_PKCS12DecoderValidateBags(p12dcx, HandleNicknameCollision);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
// Initialize slot.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
if (!slot) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
|
||||
srv = PK11_InitPin(slot, "", "");
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
}
|
||||
|
||||
// Import cert and key.
|
||||
srv = SEC_PKCS12DecoderImportBags(p12dcx);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
// User certificate must be imported from PKCS#12.
|
||||
return (mResult.mUsageFlag & nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER)
|
||||
? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult ReadBlob(/*out*/ nsCString& aBuf)
|
||||
|
@ -128,20 +262,22 @@ private:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ImportCert(CERTCertificate* aCert, const nsAString& aNickname,
|
||||
/*out*/ uint16_t* aUsageFlag)
|
||||
nsresult ImportCert(CERTCertificate* aCert)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aUsageFlag);
|
||||
|
||||
nsCString userNickname, fullNickname;
|
||||
|
||||
CopyUTF16toUTF8(aNickname, userNickname);
|
||||
CopyUTF16toUTF8(mResult.mNickname, userNickname);
|
||||
// Determine certificate nickname by adding prefix according to its type.
|
||||
if (aCert->isRoot && (aCert->nsCertType & NS_CERT_TYPE_SSL_CA)) {
|
||||
// Accept self-signed SSL CA as server certificate.
|
||||
fullNickname.AssignLiteral("WIFI_SERVERCERT_");
|
||||
fullNickname += userNickname;
|
||||
*aUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER;
|
||||
mResult.mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_SERVER;
|
||||
} else if (aCert->nsCertType & NS_CERT_TYPE_SSL_CLIENT) {
|
||||
// User Certificate
|
||||
fullNickname.AssignLiteral("WIFI_USERCERT_");
|
||||
fullNickname += userNickname;
|
||||
mResult.mUsageFlag |= nsIWifiCertService::WIFI_CERT_USAGE_FLAG_USER;
|
||||
} else {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
@ -154,7 +290,7 @@ private:
|
|||
}
|
||||
|
||||
// Import certificate, duplicated nickname will cause error.
|
||||
SECStatus srv = CERT_AddTempCertToPerm(aCert, nickname, NULL);
|
||||
SECStatus srv = CERT_AddTempCertToPerm(aCert, nickname, nullptr);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
|
|
@ -3469,7 +3469,7 @@ WifiWorker.prototype = {
|
|||
|
||||
WifiManager.importCert(msg.data, function(data) {
|
||||
if (data.status === 0) {
|
||||
let usageString = ["ServerCert"];
|
||||
let usageString = ["ServerCert", "UserCert"];
|
||||
let usageArray = [];
|
||||
for (let i = 0; i < usageString.length; i++) {
|
||||
if (data.usageFlag & (0x01 << i)) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "keyhi.h"
|
||||
#include "cryptohi.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkcs12.h"
|
||||
#include "sechash.h"
|
||||
#include "secpkcs7.h"
|
||||
#include "secport.h"
|
||||
|
@ -240,6 +241,9 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSEC_PKCS7ContentInfo,
|
|||
SEC_PKCS7ContentInfo,
|
||||
SEC_PKCS7DestroyContentInfo)
|
||||
|
||||
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedSEC_PKCS12DecoderContext,
|
||||
SEC_PKCS12DecoderContext,
|
||||
SEC_PKCS12DecoderFinish)
|
||||
namespace internal {
|
||||
|
||||
inline void
|
||||
|
|
Загрузка…
Ссылка в новой задаче