blob: 13d7e36f404ea8267c5783b2f1f8bf3a2e6177e0 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/cert/x509_util_nss.h"
#include <cert.h> // Must be included before certdb.h
#include <certdb.h>
#include <cryptohi.h>
#include <nss.h>
#include <pk11pub.h>
#include <prerror.h>
#include <secder.h>
#include <secmod.h>
#include <secport.h>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "crypto/scoped_nss_types.h"
namespace net {
namespace {
// Microsoft User Principal Name: 1.3.6.1.4.1.311.20.2.3
const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1,
0x82, 0x37, 0x14, 0x2, 0x3};
} // namespace
namespace x509_util {
void GetRFC822SubjectAltNames(CERTCertificate* cert_handle,
std::vector<std::string>* names) {
crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0));
DCHECK(alt_name.get());
names->clear();
SECStatus rv = CERT_FindCertExtension(
cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get());
if (rv != SECSuccess)
return;
crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
DCHECK(arena.get());
CERTGeneralName* alt_name_list;
alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get());
CERTGeneralName* name = alt_name_list;
while (name) {
if (name->type == certRFC822Name) {
names->push_back(
std::string(reinterpret_cast<char*>(name->name.other.data),
name->name.other.len));
}
name = CERT_GetNextGeneralName(name);
if (name == alt_name_list)
break;
}
}
void GetUPNSubjectAltNames(CERTCertificate* cert_handle,
std::vector<std::string>* names) {
crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0));
DCHECK(alt_name.get());
names->clear();
SECStatus rv = CERT_FindCertExtension(
cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get());
if (rv != SECSuccess)
return;
crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
DCHECK(arena.get());
CERTGeneralName* alt_name_list;
alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get());
CERTGeneralName* name = alt_name_list;
while (name) {
if (name->type == certOtherName) {
OtherName* on = &name->name.OthName;
if (on->oid.len == sizeof(kUpnOid) &&
memcmp(on->oid.data, kUpnOid, sizeof(kUpnOid)) == 0) {
SECItem decoded;
if (SEC_QuickDERDecodeItem(arena.get(), &decoded,
SEC_ASN1_GET(SEC_UTF8StringTemplate),
&name->name.OthName.name) == SECSuccess) {
names->push_back(
std::string(reinterpret_cast<char*>(decoded.data), decoded.len));
}
}
}
name = CERT_GetNextGeneralName(name);
if (name == alt_name_list)
break;
}
}
std::string GetUniqueNicknameForSlot(const std::string& nickname,
const SECItem* subject,
PK11SlotInfo* slot) {
int index = 2;
std::string new_name = nickname;
std::string temp_nickname = new_name;
std::string token_name;
if (!slot)
return new_name;
if (!PK11_IsInternalKeySlot(slot)) {
token_name.assign(PK11_GetTokenName(slot));
token_name.append(":");
temp_nickname = token_name + new_name;
}
while (SEC_CertNicknameConflict(temp_nickname.c_str(),
const_cast<SECItem*>(subject),
CERT_GetDefaultCertDB())) {
base::SStringPrintf(&new_name, "%s #%d", nickname.c_str(), index++);
temp_nickname = token_name + new_name;
}
return new_name;
}
} // namespace x509_util
} // namespace net