Example #1
0
SECStatus
__CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
                         CERTCertTrust *trust)
{
    NSSUTF8 *stanNick;
    PK11SlotInfo *slot;
    NSSToken *internal;
    NSSCryptoContext *context;
    nssCryptokiObject *permInstance;
    NSSCertificate *c = STAN_GetNSSCertificate(cert);
    nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
    nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
    SECStatus rv;
    PRStatus ret;

    if (c == NULL) {
        CERT_MapStanError();
        return SECFailure;
    }

    context = c->object.cryptoContext;
    if (!context) {
        PORT_SetError(SEC_ERROR_ADDING_CERT);
        return SECFailure; /* wasn't a temp cert */
    }
    stanNick = nssCertificate_GetNickname(c, NULL);
    if (stanNick && nickname && strcmp(nickname, stanNick) != 0) {
        /* different: take the new nickname */
        cert->nickname = NULL;
        nss_ZFreeIf(stanNick);
        stanNick = NULL;
    }
    if (!stanNick && nickname) {
        /* Either there was no nickname yet, or we have a new nickname */
        stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL);
    } /* else: old stanNick is identical to new nickname */
    /* Delete the temp instance */
    nssCertificateStore_Lock(context->certStore, &lockTrace);
    nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
    nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace);
    c->object.cryptoContext = NULL;
    /* Import the perm instance onto the internal token */
    slot = PK11_GetInternalKeySlot();
    internal = PK11Slot_GetNSSToken(slot);
    permInstance = nssToken_ImportCertificate(
        internal, NULL, NSSCertificateType_PKIX, &c->id, stanNick, &c->encoding,
        &c->issuer, &c->subject, &c->serial, cert->emailAddr, PR_TRUE);
    nss_ZFreeIf(stanNick);
    stanNick = NULL;
    PK11_FreeSlot(slot);
    if (!permInstance) {
        if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
            PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
        }
        return SECFailure;
    }
    nssPKIObject_AddInstance(&c->object, permInstance);
    nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
    /* reset the CERTCertificate fields */
    cert->nssCertificate = NULL;
    cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */
    if (!cert) {
        CERT_MapStanError();
        return SECFailure;
    }
    CERT_LockCertTempPerm(cert);
    cert->istemp = PR_FALSE;
    cert->isperm = PR_TRUE;
    CERT_UnlockCertTempPerm(cert);
    if (!trust) {
        return SECSuccess;
    }
    ret = STAN_ChangeCertTrust(cert, trust);
    rv = SECSuccess;
    if (ret != PR_SUCCESS) {
        rv = SECFailure;
        CERT_MapStanError();
    }
    return rv;
}
Example #2
0
CERTCertificate *
CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
                        char *nickname, PRBool isperm, PRBool copyDER)
{
    NSSCertificate *c;
    CERTCertificate *cc;
    NSSCertificate *tempCert = NULL;
    nssPKIObject *pkio;
    NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext();
    NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain();
    if (!isperm) {
        NSSDER encoding;
        NSSITEM_FROM_SECITEM(&encoding, derCert);
        /* First, see if it is already a temp cert */
        c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC,
                                                                 &encoding);
        if (!c) {
            /* Then, see if it is already a perm cert */
            c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
                                                                   &encoding);
        }
        if (c) {
            /* actually, that search ends up going by issuer/serial,
             * so it is still possible to return a cert with the same
             * issuer/serial but a different encoding, and we're
             * going to reject that
             */
            if (!nssItem_Equal(&c->encoding, &encoding, NULL)) {
                nssCertificate_Destroy(c);
                PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
                cc = NULL;
            } else {
                cc = STAN_GetCERTCertificateOrRelease(c);
                if (cc == NULL) {
                    CERT_MapStanError();
                }
            }
            return cc;
        }
    }
    pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor);
    if (!pkio) {
        CERT_MapStanError();
        return NULL;
    }
    c = nss_ZNEW(pkio->arena, NSSCertificate);
    if (!c) {
        CERT_MapStanError();
        nssPKIObject_Destroy(pkio);
        return NULL;
    }
    c->object = *pkio;
    if (copyDER) {
        nssItem_Create(c->object.arena, &c->encoding, derCert->len,
                       derCert->data);
    } else {
        NSSITEM_FROM_SECITEM(&c->encoding, derCert);
    }
    /* Forces a decoding of the cert in order to obtain the parts used
     * below
     */
    /* 'c' is not adopted here, if we fail loser frees what has been
     * allocated so far for 'c' */
    cc = STAN_GetCERTCertificate(c);
    if (!cc) {
        CERT_MapStanError();
        goto loser;
    }
    nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len,
                   cc->derIssuer.data);
    nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len,
                   cc->derSubject.data);
    if (PR_TRUE) {
        /* CERTCertificate stores serial numbers decoded.  I need the DER
        * here.  sigh.
        */
        SECItem derSerial = { 0 };
        CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
        if (!derSerial.data)
            goto loser;
        nssItem_Create(c->object.arena, &c->serial, derSerial.len,
                       derSerial.data);
        PORT_Free(derSerial.data);
    }
    if (nickname) {
        c->object.tempName =
            nssUTF8_Create(c->object.arena, nssStringType_UTF8String,
                           (NSSUTF8 *)nickname, PORT_Strlen(nickname));
    }
    if (cc->emailAddr && cc->emailAddr[0]) {
        c->email = nssUTF8_Create(
            c->object.arena, nssStringType_PrintableString,
            (NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr));
    }

    tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c);
    if (!tempCert) {
        CERT_MapStanError();
        goto loser;
    }
    /* destroy our copy */
    NSSCertificate_Destroy(c);
    /* and use the stored entry */
    c = tempCert;
    cc = STAN_GetCERTCertificateOrRelease(c);
    if (!cc) {
        /* STAN_GetCERTCertificateOrRelease destroys c on failure. */
        CERT_MapStanError();
        return NULL;
    }

    CERT_LockCertTempPerm(cc);
    cc->istemp = PR_TRUE;
    cc->isperm = PR_FALSE;
    CERT_UnlockCertTempPerm(cc);
    return cc;
loser:
    /* Perhaps this should be nssCertificate_Destroy(c) */
    nssPKIObject_Destroy(&c->object);
    return NULL;
}
Example #3
0
static void
fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
{
    CERTCertTrust *trust = NULL;
    NSSTrust *nssTrust;
    NSSCryptoContext *context = c->object.cryptoContext;
    nssCryptokiInstance *instance;
    NSSUTF8 *stanNick = NULL;

    /* We are holding the base class object's lock on entry of this function
     * This lock protects writes to fields of the CERTCertificate .
     * It is also needed by some functions to compute values such as trust.
     */
    instance = get_cert_instance(c);

    if (instance) {
        stanNick = instance->label;
    } else if (context) {
        stanNick = c->object.tempName;
    }
    /* fill other fields needed by NSS3 functions using CERTCertificate */
    if ((!cc->nickname && stanNick) || forced) {
        PRStatus nssrv;
        int nicklen, tokenlen, len;
        NSSUTF8 *tokenName = NULL;
        char *nick;
        if (instance &&
            (!PK11_IsInternalKeySlot(instance->token->pk11slot) ||
             (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
            tokenName = nssToken_GetName(instance->token);
            tokenlen = nssUTF8_Size(tokenName, &nssrv);
        } else {
            /* don't use token name for internal slot; 3.3 didn't */
            tokenlen = 0;
        }
        if (stanNick) {
            nicklen = nssUTF8_Size(stanNick, &nssrv);
            len = tokenlen + nicklen;
            nick = PORT_ArenaAlloc(cc->arena, len);
            if (tokenName) {
                memcpy(nick, tokenName, tokenlen - 1);
                nick[tokenlen - 1] = ':';
                memcpy(nick + tokenlen, stanNick, nicklen - 1);
            } else {
                memcpy(nick, stanNick, nicklen - 1);
            }
            nick[len - 1] = '\0';
            cc->nickname = nick;
        } else {
            cc->nickname = NULL;
        }
    }
    if (context) {
        /* trust */
        nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
        if (!nssTrust) {
            /* chicken and egg issue:
             *
             * c->issuer and c->serial are empty at this point, but
             * nssTrustDomain_FindTrustForCertificate use them to look up
             * up the trust object, so we point them to cc->derIssuer and
             * cc->serialNumber.
             *
             * Our caller will fill these in with proper arena copies when we
             * return. */
            c->issuer.data = cc->derIssuer.data;
            c->issuer.size = cc->derIssuer.len;
            c->serial.data = cc->serialNumber.data;
            c->serial.size = cc->serialNumber.len;
            nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c);
        }
        if (nssTrust) {
            trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
            if (trust) {
                /* we should destroy cc->trust before replacing it, but it's
                   allocated in cc->arena, so memory growth will occur on each
                   refresh */
                CERT_LockCertTrust(cc);
                cc->trust = trust;
                CERT_UnlockCertTrust(cc);
            }
            nssTrust_Destroy(nssTrust);
        }
    } else if (instance) {
        /* slot */
        if (cc->slot != instance->token->pk11slot) {
            if (cc->slot) {
                PK11_FreeSlot(cc->slot);
            }
            cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
        }
        cc->ownSlot = PR_TRUE;
        /* pkcs11ID */
        cc->pkcs11ID = instance->handle;
        /* trust */
        trust = nssTrust_GetCERTCertTrustForCert(c, cc);
        if (trust) {
            /* we should destroy cc->trust before replacing it, but it's
               allocated in cc->arena, so memory growth will occur on each
               refresh */
            CERT_LockCertTrust(cc);
            cc->trust = trust;
            CERT_UnlockCertTrust(cc);
        }
    }
    if (instance) {
        nssCryptokiObject_Destroy(instance);
    }
    /* database handle is now the trust domain */
    cc->dbhandle = c->object.trustDomain;
    /* subjectList ? */
    /* istemp and isperm are supported in NSS 3.4 */
    CERT_LockCertTempPerm(cc);
    cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
    cc->isperm = PR_TRUE;  /* by default */
    CERT_UnlockCertTempPerm(cc);
    /* pointer back */
    cc->nssCertificate = c;
    if (trust) {
        /* force the cert type to be recomputed to include trust info */
        PRUint32 nsCertType = cert_ComputeCertType(cc);

        /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
        PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
        PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType);
    }
}