/*
 * Lookup a certificate in the database by name
 */
CERTCertificate *
CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
{
    CERTName *name;
    SECItem *nameItem;
    CERTCertificate *cert = NULL;
    PRArenaPool *arena = NULL;
    
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    
    if ( arena == NULL ) {
	goto loser;
    }
    
    name = CERT_AsciiToName(nameStr);
    
    if ( name ) {
	nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
				       CERT_NameTemplate);
	if ( nameItem != NULL ) {
            cert = CERT_FindCertByName(handle, nameItem);
	}
	CERT_DestroyName(name);
    }

loser:
    if ( arena ) {
	PORT_FreeArena(arena, PR_FALSE);
    }
    
    return(cert);
}
Esempio n. 2
0
File: crlutil.c Progetto: ekr/nss
static CERTSignedCrl *
FindCRL(CERTCertDBHandle *certHandle, char *name, int type)
{
    CERTSignedCrl *crl = NULL;
    CERTCertificate *cert = NULL;
    SECItem derName;

    derName.data = NULL;
    derName.len = 0;

    cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
    if (!cert) {
        CERTName *certName = NULL;
        PLArenaPool *arena = NULL;
        SECStatus rv = SECSuccess;

        certName = CERT_AsciiToName(name);
        if (certName) {
            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
            if (arena) {
                SECItem *nameItem =
                    SEC_ASN1EncodeItem(arena, NULL, (void *)certName,
                                       SEC_ASN1_GET(CERT_NameTemplate));
                if (nameItem) {
                    rv = SECITEM_CopyItem(NULL, &derName, nameItem);
                }
                PORT_FreeArena(arena, PR_FALSE);
            }
            CERT_DestroyName(certName);
        }

        if (rv != SECSuccess) {
            SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory");
            return ((CERTSignedCrl *)NULL);
        }

        if (!derName.len || !derName.data) {
            SECU_PrintError(progName, "could not find certificate named '%s'", name);
            return ((CERTSignedCrl *)NULL);
        }
    } else {
        SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
        CERT_DestroyCertificate(cert);
    }

    crl = SEC_FindCrlByName(certHandle, &derName, type);
    if (crl == NULL)
        SECU_PrintError(progName, "could not find %s's CRL", name);
    if (derName.data) {
        SECITEM_FreeItem(&derName, PR_FALSE);
    }
    return (crl);
}
Esempio n. 3
0
/******************************************************************
 *
 * m a k e _ c e r t _ r e q u e s t
 */
static CERTCertificateRequest*
make_cert_request(char *subject, SECKEYPublicKey *pubk)
{
    CERTName * subj;
    CERTSubjectPublicKeyInfo * spki;

    CERTCertificateRequest * req;

    /* Create info about public key */
    spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
    if (!spki) {
	SECU_PrintError(progName, "unable to create subject public key");
	exit (ERRX);
    }

    subj = CERT_AsciiToName (subject);
    if (subj == NULL) {
	FatalError("Invalid data in certificate description");
    }

    /* Generate certificate request */
    req = CERT_CreateCertificateRequest(subj, spki, 0);
    if (!req) {
	SECU_PrintError(progName, "unable to make certificate request");
	exit (ERRX);
    }

    SECKEY_DestroySubjectPublicKeyInfo(spki);
    CERT_DestroyName(subj);

    if (verbosity >= 0) {
	PR_fprintf(outputFD, "certificate request generated\n");
    }

    return req;
}
static nsresult
GetAttestationCertificate(const UniquePK11SlotInfo& aSlot,
                          /*out*/ UniqueSECKEYPrivateKey& aAttestPrivKey,
                          /*out*/ UniqueCERTCertificate& aAttestCert,
                          const nsNSSShutDownPreventionLock& locker)
{
  MOZ_ASSERT(aSlot);
  if (NS_WARN_IF(!aSlot)) {
    return NS_ERROR_INVALID_ARG;
  }

  UniqueSECKEYPublicKey pubKey;

  // Construct an ephemeral keypair for this Attestation Certificate
  nsresult rv = GenEcKeypair(aSlot, aAttestPrivKey, pubKey, locker);
  if (NS_WARN_IF(NS_FAILED(rv) || !aAttestPrivKey || !pubKey)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to gen keypair, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  // Construct the Attestation Certificate itself
  UniqueCERTName subjectName(CERT_AsciiToName(kAttestCertSubjectName.get()));
  if (NS_WARN_IF(!subjectName)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to set subject name, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  UniqueCERTSubjectPublicKeyInfo spki(
    SECKEY_CreateSubjectPublicKeyInfo(pubKey.get()));
  if (NS_WARN_IF(!spki)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to set SPKI, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  UniqueCERTCertificateRequest certreq(
    CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr));
  if (NS_WARN_IF(!certreq)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to gen CSR, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  PRTime now = PR_Now();
  PRTime notBefore = now - kExpirationSlack;
  PRTime notAfter = now + kExpirationLife;

  UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
  if (NS_WARN_IF(!validity)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to gen validity, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  unsigned long serial;
  unsigned char* serialBytes =
    mozilla::BitwiseCast<unsigned char*, unsigned long*>(&serial);
  SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), serialBytes,
                                            sizeof(serial));
  if (NS_WARN_IF(srv != SECSuccess)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to gen serial, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }
  // Ensure that the most significant bit isn't set (which would
  // indicate a negative number, which isn't valid for serial
  // numbers).
  serialBytes[0] &= 0x7f;
  // Also ensure that the least significant bit on the most
  // significant byte is set (to prevent a leading zero byte,
  // which also wouldn't be valid).
  serialBytes[0] |= 0x01;

  aAttestCert = UniqueCERTCertificate(
    CERT_CreateCertificate(serial, subjectName.get(), validity.get(),
                           certreq.get()));
  if (NS_WARN_IF(!aAttestCert)) {
    MOZ_LOG(gNSSTokenLog, LogLevel::Warning,
            ("Failed to gen certificate, NSS error #%d", PORT_GetError()));
    return NS_ERROR_FAILURE;
  }

  PLArenaPool* arena = aAttestCert->arena;

  srv = SECOID_SetAlgorithmID(arena, &aAttestCert->signature,
                              SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE,
                              /* wincx */ nullptr);
  if (NS_WARN_IF(srv != SECSuccess)) {
    return NS_ERROR_FAILURE;
  }

  // Set version to X509v3.
  *(aAttestCert->version.data) = SEC_CERTIFICATE_VERSION_3;
  aAttestCert->version.len = 1;

  SECItem innerDER = { siBuffer, nullptr, 0 };
  if (NS_WARN_IF(!SEC_ASN1EncodeItem(arena, &innerDER, aAttestCert.get(),
                                     SEC_ASN1_GET(CERT_CertificateTemplate)))) {
    return NS_ERROR_FAILURE;
  }

  SECItem* signedCert = PORT_ArenaZNew(arena, SECItem);
  if (NS_WARN_IF(!signedCert)) {
    return NS_ERROR_FAILURE;
  }

  srv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
                        aAttestPrivKey.get(),
                        SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
  if (NS_WARN_IF(srv != SECSuccess)) {
    return NS_ERROR_FAILURE;
  }
  aAttestCert->derCert = *signedCert;

  MOZ_LOG(gNSSTokenLog, LogLevel::Debug,
          ("U2F Soft Token attestation certificate generated."));
  return NS_OK;
}
  nsresult Generate()
  {
    nsresult rv;

    // Get the key slot for generation later
    UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
    if (!slot) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Remove existing certs with this name (if any)
    rv = RemoveExisting();
    if (NS_FAILED(rv)) {
      return rv;
    }

    // Generate a new cert
    NS_NAMED_LITERAL_CSTRING(commonNamePrefix, "CN=");
    nsAutoCString subjectNameStr(commonNamePrefix + mNickname);
    UniqueCERTName subjectName(CERT_AsciiToName(subjectNameStr.get()));
    if (!subjectName) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Use the well-known NIST P-256 curve
    SECOidData* curveOidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
    if (!curveOidData) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Get key params from the curve
    ScopedAutoSECItem keyParams(2 + curveOidData->oid.len);
    keyParams.data[0] = SEC_ASN1_OBJECT_ID;
    keyParams.data[1] = curveOidData->oid.len;
    memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len);

    // Generate cert key pair
    SECKEYPublicKey* tempPublicKey;
    UniqueSECKEYPrivateKey privateKey(
      PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams,
                           &tempPublicKey, true /* token */,
                           true /* sensitive */, nullptr));
    UniqueSECKEYPublicKey publicKey(tempPublicKey);
    tempPublicKey = nullptr;
    if (!privateKey || !publicKey) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Create subject public key info and cert request
    UniqueCERTSubjectPublicKeyInfo spki(
      SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
    if (!spki) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }
    UniqueCERTCertificateRequest certRequest(
      CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr));
    if (!certRequest) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Valid from one day before to 1 year after
    static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
                               * PRTime(60)  // sec
                               * PRTime(60)  // min
                               * PRTime(24); // hours

    PRTime now = PR_Now();
    PRTime notBefore = now - oneDay;
    PRTime notAfter = now + (PRTime(365) * oneDay);
    UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
    if (!validity) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Generate random serial
    unsigned long serial;
    // This serial in principle could collide, but it's unlikely
    rv = MapSECStatus(PK11_GenerateRandomOnSlot(
           slot.get(), BitwiseCast<unsigned char*, unsigned long*>(&serial),
           sizeof(serial)));
    if (NS_FAILED(rv)) {
      return rv;
    }

    // Create the cert from these pieces
    UniqueCERTCertificate cert(
      CERT_CreateCertificate(serial, subjectName.get(), validity.get(),
                             certRequest.get()));
    if (!cert) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Update the cert version to X509v3
    if (!cert->version.data) {
      return NS_ERROR_INVALID_POINTER;
    }
    *(cert->version.data) = SEC_CERTIFICATE_VERSION_3;
    cert->version.len = 1;

    // Set cert signature algorithm
    PLArenaPool* arena = cert->arena;
    if (!arena) {
      return NS_ERROR_INVALID_POINTER;
    }
    rv = MapSECStatus(
           SECOID_SetAlgorithmID(arena, &cert->signature,
                                 SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0));
    if (NS_FAILED(rv)) {
      return rv;
    }

    // Encode and self-sign the cert
    UniqueSECItem certDER(
      SEC_ASN1EncodeItem(nullptr, nullptr, cert.get(),
                         SEC_ASN1_GET(CERT_CertificateTemplate)));
    if (!certDER) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }
    rv = MapSECStatus(
           SEC_DerSignData(arena, &cert->derCert, certDER->data, certDER->len,
                           privateKey.get(),
                           SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE));
    if (NS_FAILED(rv)) {
      return rv;
    }

    // Create a CERTCertificate from the signed data
    UniqueCERTCertificate certFromDER(
      CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &cert->derCert, nullptr,
                              true /* perm */, true /* copyDER */));
    if (!certFromDER) {
      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    }

    // Save the cert in the DB
    rv = MapSECStatus(PK11_ImportCert(slot.get(), certFromDER.get(),
                                      CK_INVALID_HANDLE, mNickname.get(),
                                      false /* unused */));
    if (NS_FAILED(rv)) {
      return rv;
    }

    // We should now have cert in the DB, read it back in nsIX509Cert form
    return GetFromDB();
  }
/*
 * FUNCTION: PKIX_PL_GeneralName_Create (see comments in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_GeneralName_Create(
        PKIX_UInt32 nameType,
        PKIX_PL_String *stringRep,
        PKIX_PL_GeneralName **pGName,
        void *plContext)
{
        PKIX_PL_X500Name *pkixDN = NULL;
        PKIX_PL_OID *pkixOID = NULL;
        SECItem *secItem = NULL;
        char *asciiString = NULL;
        PKIX_UInt32 length = 0;
        PKIX_PL_GeneralName *genName = NULL;
        CERTGeneralName *nssGenName = NULL;
        CERTGeneralNameList *nssGenNameList = NULL;
        CERTName *nssCertName = NULL;
        PLArenaPool *arena = NULL;

        PKIX_ENTER(GENERALNAME, "PKIX_PL_GeneralName_Create");
        PKIX_NULLCHECK_TWO(pGName, stringRep);

        PKIX_CHECK(PKIX_PL_String_GetEncoded
                    (stringRep,
                    PKIX_ESCASCII,
                    (void **)&asciiString,
                    &length,
                    plContext),
                    PKIX_STRINGGETENCODEDFAILED);

        /* Create a temporary CERTGeneralName */
        PKIX_GENERALNAME_DEBUG("\t\tCalling PL_strlen).\n");
        length = PL_strlen(asciiString);
        PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_AllocItem).\n");
        secItem = SECITEM_AllocItem(NULL, NULL, length);
        PKIX_GENERALNAME_DEBUG("\t\tCalling PORT_Memcpy).\n");
        (void) PORT_Memcpy(secItem->data, asciiString, length);
        PKIX_CERT_DEBUG("\t\tCalling PORT_NewArena).\n");
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
        if (arena == NULL) {
                PKIX_ERROR(PKIX_OUTOFMEMORY);
        }
        PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_NewGeneralName).\n");
        nssGenName = CERT_NewGeneralName(arena, nameType);
        if (nssGenName == NULL) {
                PKIX_ERROR(PKIX_ALLOCATENEWCERTGENERALNAMEFAILED);
        }

        switch (nameType) {
        case certRFC822Name:
        case certDNSName:
        case certURI:
                nssGenName->name.other = *secItem;
                break;

        case certDirectoryName:

                PKIX_CHECK(PKIX_PL_X500Name_Create
                            (stringRep, &pkixDN, plContext),
                            PKIX_X500NAMECREATEFAILED);

                PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_AsciiToName).\n");
                nssCertName = CERT_AsciiToName(asciiString);
                nssGenName->name.directoryName = *nssCertName;
                break;

        case certRegisterID:
                PKIX_CHECK(PKIX_PL_OID_Create
                            (asciiString, &pkixOID, plContext),
                            PKIX_OIDCREATEFAILED);
                nssGenName->name.other = *secItem;
                break;
        default:
                /* including IPAddress, EDIPartyName, OtherName, X400Address */
                PKIX_ERROR(PKIX_UNABLETOCREATEGENERALNAMEOFTHISTYPE);
        }

        /* create a PKIX_PL_GeneralName object */
        PKIX_CHECK(PKIX_PL_Object_Alloc
                    (PKIX_GENERALNAME_TYPE,
                    sizeof (PKIX_PL_GeneralName),
                    (PKIX_PL_Object **)&genName,
                    plContext),
                    PKIX_COULDNOTCREATEOBJECT);

        /* create a CERTGeneralNameList */
        nssGenName->type = nameType;
        PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n");
        nssGenNameList = CERT_CreateGeneralNameList(nssGenName);
        if (nssGenNameList == NULL) {
                PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED);
        }
        genName->nssGeneralNameList = nssGenNameList;

        /* initialize fields */
        genName->type = nameType;
        genName->directoryName = pkixDN;
        genName->OthName = NULL;
        genName->other = secItem;
        genName->oid = pkixOID;

        *pGName = genName;
cleanup:

        PKIX_FREE(asciiString);

        if (nssCertName != NULL) {
                PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyName).\n");
                CERT_DestroyName(nssCertName);
        }

        if (arena){ /* will free nssGenName */
                PKIX_CERT_DEBUG("\t\tCalling PORT_FreeArena).\n");
                PORT_FreeArena(arena, PR_FALSE);
        }

        if (PKIX_ERROR_RECEIVED){
                PKIX_DECREF(pkixDN);
                PKIX_DECREF(pkixOID);

                PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
                if (secItem){
                        SECITEM_FreeItem(secItem, PR_TRUE);
                        secItem = NULL;
                }
        }

        PKIX_RETURN(GENERALNAME);
}
Esempio n. 7
0
RefPtr<DtlsIdentity> DtlsIdentity::Generate() {
    UniquePK11SlotInfo slot(PK11_GetInternalSlot());
    if (!slot) {
        return nullptr;
    }

    uint8_t random_name[16];

    SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name,
                   sizeof(random_name));
    if (rv != SECSuccess)
        return nullptr;

    std::string name;
    char chunk[3];
    for (size_t i = 0; i < sizeof(random_name); ++i) {
        SprintfLiteral(chunk, "%.2x", random_name[i]);
        name += chunk;
    }

    std::string subject_name_string = "CN=" + name;
    UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str()));
    if (!subject_name) {
        return nullptr;
    }

    unsigned char paramBuf[12]; // OIDs are small
    SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) };
    SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
    if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) {
        return nullptr;
    }
    ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID;
    ecdsaParams.data[1] = oidData->oid.len;
    memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len);
    ecdsaParams.len = oidData->oid.len + 2;

    SECKEYPublicKey *pubkey;
    UniqueSECKEYPrivateKey private_key(
        PK11_GenerateKeyPair(slot.get(),
                             CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey,
                             PR_FALSE, PR_TRUE, nullptr));
    if (private_key == nullptr)
        return nullptr;
    UniqueSECKEYPublicKey public_key(pubkey);
    pubkey = nullptr;

    UniqueCERTSubjectPublicKeyInfo spki(
        SECKEY_CreateSubjectPublicKeyInfo(public_key.get()));
    if (!spki) {
        return nullptr;
    }

    UniqueCERTCertificateRequest certreq(
        CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr));
    if (!certreq) {
        return nullptr;
    }

    // From 1 day before todayto 30 days after.
    // This is a sort of arbitrary range designed to be valid
    // now with some slack in case the other side expects
    // some before expiry.
    //
    // Note: explicit casts necessary to avoid
    //       warning C4307: '*' : integral constant overflow
    static const PRTime oneDay = PRTime(PR_USEC_PER_SEC)
                                 * PRTime(60)  // sec
                                 * PRTime(60)  // min
                                 * PRTime(24); // hours
    PRTime now = PR_Now();
    PRTime notBefore = now - oneDay;
    PRTime notAfter = now + (PRTime(30) * oneDay);

    UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter));
    if (!validity) {
        return nullptr;
    }

    unsigned long serial;
    // Note: This serial in principle could collide, but it's unlikely
    rv = PK11_GenerateRandomOnSlot(slot.get(),
                                   reinterpret_cast<unsigned char *>(&serial),
                                   sizeof(serial));
    if (rv != SECSuccess) {
        return nullptr;
    }

    UniqueCERTCertificate certificate(
        CERT_CreateCertificate(serial, subject_name.get(), validity.get(),
                               certreq.get()));
    if (!certificate) {
        return nullptr;
    }

    PLArenaPool *arena = certificate->arena;

    rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
                               SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0);
    if (rv != SECSuccess)
        return nullptr;

    // Set version to X509v3.
    *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3;
    certificate->version.len = 1;

    SECItem innerDER;
    innerDER.len = 0;
    innerDER.data = nullptr;

    if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(),
                            SEC_ASN1_GET(CERT_CertificateTemplate))) {
        return nullptr;
    }

    SECItem *signedCert = PORT_ArenaZNew(arena, SECItem);
    if (!signedCert) {
        return nullptr;
    }

    rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len,
                         private_key.get(),
                         SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
    if (rv != SECSuccess) {
        return nullptr;
    }
    certificate->derCert = *signedCert;

    RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key),
            Move(certificate),
            ssl_kea_ecdh);
    return identity.forget();
}