Ejemplo n.º 1
0
/* decodes the authenticated safe item.  a return of NULL indicates
 * an error.  however, the error will have occurred either in memory
 * allocation or in decoding the authenticated safe.
 *
 * if an old PFX item has been found, we want to convert the
 * old authenticated safe to the new one.
 */
static SEC_PKCS12AuthenticatedSafe *
sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx) 
{
    SECItem *der_asafe = NULL;
    SEC_PKCS12AuthenticatedSafe *asafe = NULL;
    SECStatus rv;

    if(pfx == NULL) {
	return NULL;
    }

    der_asafe = SEC_PKCS7GetContent(&pfx->authSafe);
    if(der_asafe == NULL) {
	/* XXX set error ? */
	goto loser;
    }

    asafe = sec_pkcs12_new_asafe(pfx->poolp);
    if(asafe == NULL) {
	goto loser;
    }

    if(pfx->old == PR_FALSE) {
	rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 
			 	SEC_PKCS12AuthenticatedSafeTemplate, 
			 	der_asafe);
	asafe->old = PR_FALSE;
	asafe->swapUnicode = pfx->swapUnicode;
    } else {
	/* handle beta exported files */
	rv = SEC_ASN1DecodeItem(pfx->poolp, asafe, 
				SEC_PKCS12AuthenticatedSafeTemplate_OLD,
				der_asafe);
	asafe->safe = &(asafe->old_safe);
	rv = sec_pkcs12_convert_old_auth_safe(asafe);
	asafe->old = PR_TRUE;
    }

    if(rv != SECSuccess) {
	goto loser;
    }

    asafe->poolp = pfx->poolp;
    
    return asafe;

loser:
    return NULL;
}
Ejemplo n.º 2
0
/* decode the DER encoded PFX item.  if unable to decode, check to see if it
 * is an older PFX item.  If that fails, assume the file was not a valid
 * pfx file.
 * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX
 */
static SEC_PKCS12PFXItem *
sec_pkcs12_decode_pfx(SECItem *der_pfx)
{
    SEC_PKCS12PFXItem *pfx;
    SECStatus rv;

    if(der_pfx == NULL) {
	return NULL;
    }

    /* allocate the space for a new PFX item */
    pfx = sec_pkcs12_new_pfx();
    if(pfx == NULL) {
	return NULL;
    }

    rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate, 
    			    der_pfx);

    /* if a failure occurred, check for older version...
     * we also get rid of the old pfx structure, because we don't
     * know where it failed and what data in may contain
     */
    if(rv != SECSuccess) {
	SEC_PKCS12DestroyPFX(pfx);
	pfx = sec_pkcs12_new_pfx();
	if(pfx == NULL) {
	    return NULL;
	}
	rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, 
				der_pfx);
	if(rv != SECSuccess) {
	    PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX);
	    PORT_FreeArena(pfx->poolp, PR_TRUE);
	    return NULL;
	}
	pfx->old = PR_TRUE;
	SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac);
	SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt);
    } else {
	pfx->old = PR_FALSE;
    }

    /* convert bit string from bits to bytes */
    pfx->macData.macSalt.len /= 8;

    return pfx;
}
Ejemplo n.º 3
0
SECStatus
PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI, 
	SECItem *nickname, SECItem *publicValue, PRBool isPerm, 
	PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey** privk,
	void *wincx) 
{
    SECKEYPrivateKeyInfo *pki = NULL;
    PRArenaPool *temparena = NULL;
    SECStatus rv = SECFailure;

    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!temparena)
        return rv;
    pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo);
    if (!pki) {
        PORT_FreeArena(temparena, PR_FALSE);
        return rv;
    }
    pki->arena = temparena;

    rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate,
		derPKI);
    if( rv != SECSuccess ) {
	goto finish;
    }

    rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
		publicValue, isPerm, isPrivate, keyUsage, privk, wincx);

finish:
    /* this zeroes the key and frees the arena */
    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/);
    return rv;
}
Ejemplo n.º 4
0
/*
 * SecSMIMEGetCertFromEncryptionKeyPreference -
 *				find cert marked by EncryptionKeyPreference attribute
 *
 * "keychainOrArray" - handle for the cert database to look in
 * "DERekp" - DER-encoded value of S/MIME Encryption Key Preference attribute
 *
 * if certificate is supposed to be found among the message's included certificates,
 * they are assumed to have been imported already.
 */
SecCertificateRef
SecSMIMEGetCertFromEncryptionKeyPreference(SecKeychainRef keychainOrArray, CSSM_DATA_PTR DERekp)
{
    PLArenaPool *tmppoolp = NULL;
    SecCertificateRef cert = NULL;
    NSSSMIMEEncryptionKeyPreference ekp;

    tmppoolp = PORT_NewArena(1024);
    if (tmppoolp == NULL)
	return NULL;

    /* decode DERekp */
    if (SEC_ASN1DecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, DERekp) != SECSuccess)
	goto loser;

    /* find cert */
    switch (ekp.selector) {
    case NSSSMIMEEncryptionKeyPref_IssuerSN:
	cert = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, ekp.id.issuerAndSN);
	break;
    case NSSSMIMEEncryptionKeyPref_RKeyID:
    case NSSSMIMEEncryptionKeyPref_SubjectKeyID:
	/* XXX not supported yet - we need to be able to look up certs by SubjectKeyID */
	break;
    default:
	PORT_Assert(0);
    }
loser:
    if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE);

    return cert;
}
Ejemplo n.º 5
0
/*
 * Host name checking according to RFC 2595.
 */
static enum okay
nss_check_host(const char *server, struct sock *sp)
{
	CERTCertificate	*cert;
	char	*cn = NULL;
	enum okay	ok = STOP;
	PRArenaPool	*arena;
	CERTGeneralName	*gn;
	SECItem	altname;
	CERTAltNameEncodedContext	ec;
	int	i;
	const SEC_ASN1Template	gntempl[] = {
		{ SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
	};

	if ((cert = SSL_PeerCertificate(sp->s_prfd)) == NULL) {
		fprintf(stderr, "no certificate from \"%s\"\n", server);
		return STOP;
	}
	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
	if (CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
				&altname) == SECSuccess &&
			SEC_ASN1DecodeItem(arena, &ec, gntempl,
				&altname) == SECSuccess &&
			ec.encodedGenName != NULL) {
		for (i = 0; ec.encodedGenName[i] != NULL; i++) {
			gn = CERT_DecodeGeneralName(arena, ec.encodedGenName[i],
					NULL);
			if (gn->type == certDNSName) {
				char	*dn = ac_alloc(gn->name.other.len + 1);
				memcpy(dn, gn->name.other.data,
						gn->name.other.len);
				dn[gn->name.other.len] = '\0';
				if (verbose)
					fprintf(stderr,
						"Comparing DNS name: \"%s\"\n",
						dn);
				if (rfc2595_hostname_match(server, dn)
						== OKAY) {
					ac_free(dn);
					goto out;
				}
				ac_free(dn);
			}
		}
	}
	if ((cn = CERT_GetCommonName(&cert->subject)) != NULL) {
		if (verbose)
			fprintf(stderr, "Comparing common name: \"%s\"\n", cn);
		ok = rfc2595_hostname_match(server, cn);
	}
	if (ok == STOP)
		fprintf(stderr, "host certificate does not match \"%s\"\n",
				server);
out:	if (cn)
		PORT_Free(cn);
	PORT_FreeArena(arena, PR_FALSE);
	CERT_DestroyCertificate(cert);
	return ok;
}
Ejemplo n.º 6
0
int
sv_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena,
                             CERTSubjectPublicKeyInfo *i, char *msg)
{
    SECKEYPublicKey *pk;
    int rv;
    char mm[200];

    sprintf(mm, "%s.publicKeyAlgorithm=", msg);
    sv_PrintAlgorithmID(out, &i->algorithm, mm);

    pk = (SECKEYPublicKey *)PORT_ZAlloc(sizeof(SECKEYPublicKey));
    if (!pk)
        return PORT_GetError();

    DER_ConvertBitString(&i->subjectPublicKey);
    switch (SECOID_FindOIDTag(&i->algorithm.algorithm)) {
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
            rv = SEC_ASN1DecodeItem(arena, pk,
                                    SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate),
                                    &i->subjectPublicKey);
            if (rv)
                return rv;
            sprintf(mm, "%s.rsaPublicKey.", msg);
            sv_PrintRSAPublicKey(out, pk, mm);
            break;
        case SEC_OID_ANSIX9_DSA_SIGNATURE:
            rv = SEC_ASN1DecodeItem(arena, pk,
                                    SEC_ASN1_GET(SECKEY_DSAPublicKeyTemplate),
                                    &i->subjectPublicKey);
            if (rv)
                return rv;
            sprintf(mm, "%s.dsaPublicKey.", msg);
            sv_PrintDSAPublicKey(out, pk, mm);
            break;
        default:
            fprintf(out, "%s=bad SPKI algorithm type\n", msg);
            return 0;
    }

    return 0;
}
Ejemplo n.º 7
0
int
sv_PrintCertificate(FILE *out, SECItem *der, char *m, int level)
{
    PLArenaPool *arena = NULL;
    CERTCertificate *c;
    int rv;
    int iv;
    char mm[200];

    /* Decode certificate */
    c = (CERTCertificate *)PORT_ZAlloc(sizeof(CERTCertificate));
    if (!c)
        return PORT_GetError();

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena)
        return SEC_ERROR_NO_MEMORY;

    rv = SEC_ASN1DecodeItem(arena, c, SEC_ASN1_GET(CERT_CertificateTemplate),
                            der);
    if (rv) {
        PORT_FreeArena(arena, PR_FALSE);
        return rv;
    }

    /* Pretty print it out */
    iv = DER_GetInteger(&c->version);
    fprintf(out, "%sversion=%d (0x%x)\n", m, iv + 1, iv);
    sprintf(mm, "%sserialNumber=", m);
    sv_PrintInteger(out, &c->serialNumber, mm);
    sprintf(mm, "%ssignatureAlgorithm=", m);
    sv_PrintAlgorithmID(out, &c->signature, mm);
    sprintf(mm, "%sissuerName=", m);
    sv_PrintName(out, &c->issuer, mm);
    sprintf(mm, "%svalidity.", m);
    sv_PrintValidity(out, &c->validity, mm);
    sprintf(mm, "%ssubject=", m);
    sv_PrintName(out, &c->subject, mm);
    sprintf(mm, "%ssubjectPublicKeyInfo", m);
    rv = sv_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, mm);
    if (rv) {
        PORT_FreeArena(arena, PR_FALSE);
        return rv;
    }
    sprintf(mm, "%ssignedExtensions.", m);
    sv_PrintExtensions(out, c->extensions, mm);

    PORT_FreeArena(arena, PR_FALSE);
    return 0;
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_DecodeCrossCertPair
 * DESCRIPTION:
 *
 *  This function decodes a DER-encoded CrossCertPair pointed to by
 *  "responseList" and extracts and decodes the Certificates in that pair,
 *  adding the resulting Certs, if the decoding was successful, to the List
 *  (possibly empty) pointed to by "certList". If none of the objects
 *  can be decoded into a Cert, the List is returned unchanged.
 *
 * PARAMETERS:
 *  "derCCPItem"
 *      The address of the SECItem containing the DER representation of the
 *      CrossCertPair. Must be non-NULL.
 *  "certList"
 *      The address of the List to which the decoded Certs are added. May be
 *      empty, but must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CertStore Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
PKIX_Error *
pkix_pl_LdapCertStore_DecodeCrossCertPair(
        SECItem *derCCPItem,
        PKIX_List *certList,
        void *plContext)
{
        LDAPCertPair certPair = {{ siBuffer, NULL, 0 }, { siBuffer, NULL, 0 }};
        SECStatus rv = SECFailure;

        PRArenaPool *tempArena = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DecodeCrossCertPair");
        PKIX_NULLCHECK_TWO(derCCPItem, certList);

        tempArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
        if (!tempArena) {
            PKIX_ERROR(PKIX_OUTOFMEMORY);
        }

        rv = SEC_ASN1DecodeItem(tempArena, &certPair, PKIX_PL_LDAPCrossCertPairTemplate,
                                derCCPItem);
        if (rv != SECSuccess) {
                goto cleanup;
        }

        if (certPair.forward.data != NULL) {

            PKIX_CHECK(
                pkix_pl_Cert_CreateToList(&certPair.forward, certList,
                                          plContext),
                PKIX_CERTCREATETOLISTFAILED);
        }

        if (certPair.reverse.data != NULL) {

            PKIX_CHECK(
                pkix_pl_Cert_CreateToList(&certPair.reverse, certList,
                                          plContext),
                PKIX_CERTCREATETOLISTFAILED);
        }

cleanup:
        if (tempArena) {
            PORT_FreeArena(tempArena, PR_FALSE);
        }

        PKIX_RETURN(CERTSTORE);
}
Ejemplo n.º 9
0
SECStatus
PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI,
                                         SECItem *nickname, SECItem *publicValue,
                                         PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
                                         SECKEYPrivateKey **privk, void *wincx)
{
    SECKEYPrivateKeyInfo *pki = NULL;
    PLArenaPool *temparena = NULL;
    SECStatus rv = SECFailure;

    temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!temparena)
        return rv;
    pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo);
    if (!pki) {
        PORT_FreeArena(temparena, PR_FALSE);
        return rv;
    }
    pki->arena = temparena;

    rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate,
                            derPKI);
    if (rv != SECSuccess) {
        /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
         * validity of the data in pki. The best we can do is free the arena
         * and return. */
        PORT_FreeArena(temparena, PR_TRUE);
        return rv;
    }
    if (pki->privateKey.data == NULL) {
        /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey
         * is a zero-length octet string, free the arena and return a failure
         * to avoid trying to zero the corresponding SECItem in
         * SECKEY_DestroyPrivateKeyInfo(). */
        PORT_FreeArena(temparena, PR_TRUE);
        PORT_SetError(SEC_ERROR_BAD_KEY);
        return SECFailure;
    }

    rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
                                               publicValue, isPerm, isPrivate,
                                               keyUsage, privk, wincx);

    /* this zeroes the key and frees the arena */
    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/);
    return rv;
}
Ejemplo n.º 10
0
/* extract the safe from the authenticated safe.
 *  if we are unable to decode the safe, then it is likely that the 
 *  safe has not been decrypted or the password used to decrypt
 *  the safe was invalid.  we assume that the password was invalid and
 *  set an error accordingly.
 * a return of NULL indicates that an error occurred.
 */
static SEC_PKCS12SafeContents *
sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe)
{
    SECItem *src = NULL;
    SEC_PKCS12SafeContents *safe = NULL;
    SECStatus rv = SECFailure;

    if(asafe == NULL) {
	return NULL;
    }

    safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp, 
	    					sizeof(SEC_PKCS12SafeContents));
    if(safe == NULL) {
	return NULL;
    }
    safe->poolp = asafe->poolp;
    safe->old = asafe->old;
    safe->swapUnicode = asafe->swapUnicode;

    src = SEC_PKCS7GetContent(asafe->safe);
    if(src != NULL) {
	const SEC_ASN1Template *theTemplate;
	if(asafe->old != PR_TRUE) {
	    theTemplate = SEC_PKCS12SafeContentsTemplate;
	} else {
	    theTemplate = SEC_PKCS12SafeContentsTemplate_OLD;
	}

	rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src);

	/* if we could not decode the item, password was probably invalid */
	if(rv != SECSuccess) {
	    safe = NULL;
	    PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT);
	}
    } else {
	PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
	rv = SECFailure;
    }

    return safe;
}
Ejemplo n.º 11
0
int
sv_PrintSignedData(FILE *out, SECItem *der, char *m, SECU_PPFunc inner)
{
    PLArenaPool *arena = NULL;
    CERTSignedData *sd;
    int rv;

    /* Strip off the signature */
    sd = (CERTSignedData *)PORT_ZAlloc(sizeof(CERTSignedData));
    if (!sd)
        return PORT_GetError();

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena)
        return SEC_ERROR_NO_MEMORY;

    rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate),
                            der);
    if (rv) {
        PORT_FreeArena(arena, PR_FALSE);
        return rv;
    }

    /*    fprintf(out, "%s:\n", m); */
    PORT_Strcat(m, "data.");

    rv = (*inner)(out, &sd->data, m, 0);
    if (rv) {
        PORT_FreeArena(arena, PR_FALSE);
        return rv;
    }

    m[PORT_Strlen(m) - 5] = 0;
    fprintf(out, "%s", m);
    sv_PrintAlgorithmID(out, &sd->signatureAlgorithm, "signatureAlgorithm=");
    DER_ConvertBitString(&sd->signature);
    fprintf(out, "%s", m);
    sv_PrintAsHex(out, &sd->signature, "signature=");

    PORT_FreeArena(arena, PR_FALSE);
    return 0;
}
Ejemplo n.º 12
0
static SECItem *
crmf_decode_params(SECItem *inParams)
{
    SECItem *params;
    SECStatus rv = SECFailure;
    PLArenaPool *poolp;

    poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
    if (poolp == NULL) {
        return NULL;
    }

    params = PORT_ArenaZNew(poolp, SECItem);
    if (params) {
        rv = SEC_ASN1DecodeItem(poolp, params,
                                SEC_ASN1_GET(SEC_OctetStringTemplate),
                                inParams);
    }
    params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL;
    PORT_FreeArena(poolp, PR_FALSE);
    return params;
}
Ejemplo n.º 13
0
SECStatus CERT_FindInvalidDateExten (CERTCrl *crl, int64 *value)
{
    SECItem encodedExtenValue;
    SECItem decodedExtenValue = {siBuffer,0};
    SECStatus rv;

    encodedExtenValue.data = decodedExtenValue.data = NULL;
    encodedExtenValue.len = decodedExtenValue.len = 0;

    rv = cert_FindExtension
	 (crl->extensions, SEC_OID_X509_INVALID_DATE, &encodedExtenValue);
    if ( rv != SECSuccess )
	return (rv);

    rv = SEC_ASN1DecodeItem (NULL, &decodedExtenValue,
			     SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
                             &encodedExtenValue);
    if (rv == SECSuccess)
	rv = DER_GeneralizedTimeToTime(value, &encodedExtenValue);
    PORT_Free (decodedExtenValue.data);
    PORT_Free (encodedExtenValue.data);
    return (rv);
}
Ejemplo n.º 14
0
SECStatus
sv_PrintInvalidDateExten(FILE *out, SECItem *value, char *msg)
{
    SECItem decodedValue;
    SECStatus rv;
    PRTime invalidTime;
    char *formattedTime = NULL;

    decodedValue.data = NULL;
    rv = SEC_ASN1DecodeItem(NULL, &decodedValue,
                            SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
                            value);
    if (rv == SECSuccess) {
        rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue);
        if (rv == SECSuccess) {
            formattedTime = CERT_GenTime2FormattedAscii(invalidTime, "%a %b %d %H:%M:%S %Y");
            fprintf(out, "%s: %s\n", msg, formattedTime);
            PORT_Free(formattedTime);
        }
    }
    PORT_Free(decodedValue.data);

    return (rv);
}
Ejemplo n.º 15
0
PK11SymKey *
NSS_CMSUtil_DecryptSymKey_MISSI(SECKEYPrivateKey *privkey, SECItem *encKey, SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg)
{
    /* fortezza: do a key exchange */
    SECStatus err;
    CK_MECHANISM_TYPE bulkType;
    PK11SymKey *tek;
    SECKEYPublicKey *originatorPubKey;
    NSSCMSSMIMEKEAParameters keaParams;
    PK11SymKey *bulkkey;
    int bulkLength;

    (void) memset(&keaParams, 0, sizeof(keaParams));

    /* NOTE: this uses the SMIME v2 recipientinfo for compatibility.
       All additional KEA parameters are DER-encoded in the encryption algorithm parameters */

    /* Decode the KEA algorithm parameters. */
    err = SEC_ASN1DecodeItem(NULL, &keaParams, NSS_SMIMEKEAParamTemplateAllParams,
			     &(keyEncAlg->parameters));
    if (err != SECSuccess)
	goto loser;

    /* get originator's public key */
   originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
			   keaParams.originatorKEAKey.len);
   if (originatorPubKey == NULL)
	  goto loser;
    
   /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
      The Derive function generates a shared secret and combines it with the originatorRA
      data to come up with an unique session key */
   tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
			 &keaParams.originatorRA, NULL,
			 CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
			 CKA_WRAP, 0, pwfn_arg);
   SECKEY_DestroyPublicKey(originatorPubKey);	/* not needed anymore */
   if (tek == NULL)
	goto loser;
    
    /* Now that we have the TEK, unwrap the bulk key
       with which to decrypt the message. We have to
       do one of two different things depending on 
       whether Skipjack was used for *bulk* encryption 
       of the message. */
    bulkType = PK11_AlgtagToMechanism(bulkalgtag);
    switch (bulkType) {
    case CKM_SKIPJACK_CBC64:
    case CKM_SKIPJACK_ECB64:
    case CKM_SKIPJACK_OFB64:
    case CKM_SKIPJACK_CFB64:
    case CKM_SKIPJACK_CFB32:
    case CKM_SKIPJACK_CFB16:
    case CKM_SKIPJACK_CFB8:
	/* Skipjack is being used as the bulk encryption algorithm.*/
	/* Unwrap the bulk key. */
	bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
				    encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
	break;
    default:
	/* Skipjack was not used for bulk encryption of this
	   message. Use Skipjack CBC64, with the nonSkipjackIV
	   part of the KEA key parameters, to decrypt 
	   the bulk key. If the optional parameter bulkKeySize is present,
	   bulk key size is different than the encrypted key size */
	if (keaParams.bulkKeySize.len > 0) {
	    err = SEC_ASN1DecodeItem(NULL, &bulkLength,
				     SEC_ASN1_GET(SEC_IntegerTemplate),
				     &keaParams.bulkKeySize);
	    if (err != SECSuccess)
		goto loser;
	}
	
	bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64, &keaParams.nonSkipjackIV, 
				    encKey, bulkType, CKA_DECRYPT, bulkLength);
	break;
    }
    return bulkkey;
loser:
    return NULL;
}
Ejemplo n.º 16
0
static SecCmsCipherContext *
SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, PRBool encrypt)
{
    SecCmsCipherContext *cc;
    CSSM_CC_HANDLE ciphercc = 0;
    SECOidData *oidData;
    SECOidTag algtag;
    CSSM_ALGORITHMS algorithm;
    CSSM_PADDING padding = CSSM_PADDING_PKCS7;
    CSSM_ENCRYPT_MODE mode;
    CSSM_CSP_HANDLE cspHandle;
    const CSSM_KEY *cssmKey;
    OSStatus rv;
    uint8 ivbuf[8];
    CSSM_DATA initVector = { sizeof(ivbuf), ivbuf };
    //CSSM_CONTEXT_ATTRIBUTE contextAttribute = { CSSM_ATTRIBUTE_ALG_PARAMS, sizeof(CSSM_DATA_PTR) };

    rv = SecKeyGetCSPHandle(key, &cspHandle);
    if (rv)
	goto loser;
    rv = SecKeyGetCSSMKey(key, &cssmKey);
    if (rv)
	goto loser;

    // @@@ Add support for PBE based stuff

    oidData = SECOID_FindOID(&algid->algorithm);
    if (!oidData)
	goto loser;
    algtag = oidData->offset;
    algorithm = oidData->cssmAlgorithm;
    if (!algorithm)
	goto loser;

    switch (algtag)
    {
    case SEC_OID_RC2_CBC:
    case SEC_OID_RC4:
    case SEC_OID_DES_EDE3_CBC:
    case SEC_OID_DES_EDE:
    case SEC_OID_DES_CBC:
    case SEC_OID_RC5_CBC_PAD:
    case SEC_OID_AES_128_CBC:
    case SEC_OID_AES_192_CBC:
    case SEC_OID_AES_256_CBC:
    case SEC_OID_FORTEZZA_SKIPJACK:
	mode = CSSM_ALGMODE_CBCPadIV8;
	break;

    case SEC_OID_DES_ECB:
    case SEC_OID_AES_128_ECB:
    case SEC_OID_AES_192_ECB:
    case SEC_OID_AES_256_ECB:
	mode = CSSM_ALGMODE_ECBPad;
	break;

    case SEC_OID_DES_OFB:
	mode = CSSM_ALGMODE_OFBPadIV8;
	break;

    case SEC_OID_DES_CFB:
	mode = CSSM_ALGMODE_CFBPadIV8;
	break;

    default:
	goto loser;
    }

    if (encrypt)
    {
	CSSM_CC_HANDLE randomcc;
	//SECItem *parameters;

	// Generate random initVector
	if (CSSM_CSP_CreateRandomGenContext(cspHandle,
		CSSM_ALGID_APPLE_YARROW,
		NULL, /* seed*/
		initVector.Length,
		&randomcc))
	    goto loser;

	if (CSSM_GenerateRandom(randomcc, &initVector))
	    goto loser;
	CSSM_DeleteContext(randomcc);

	// Put IV into algid.parameters
	switch (algtag)
	{
	case SEC_OID_RC4:
	case SEC_OID_DES_EDE3_CBC:
	case SEC_OID_DES_EDE:
	case SEC_OID_DES_CBC:
	case SEC_OID_AES_128_CBC:
	case SEC_OID_AES_192_CBC:
	case SEC_OID_AES_256_CBC:
	case SEC_OID_FORTEZZA_SKIPJACK:
	case SEC_OID_DES_ECB:
	case SEC_OID_AES_128_ECB:
	case SEC_OID_AES_192_ECB:
	case SEC_OID_AES_256_ECB:
	case SEC_OID_DES_OFB:
	case SEC_OID_DES_CFB:
	    /* Just encode the initVector as an octet string. */
	    if (!SEC_ASN1EncodeItem(poolp, &algid->parameters,
				    &initVector, SEC_OctetStringTemplate))
		goto loser;
	    break;
    
	case SEC_OID_RC2_CBC:
	{
	    sec_rc2cbcParameter rc2 = {};
	    unsigned long rc2version;
	    SECItem *newParams;

	    rc2.iv = initVector;
	    rc2version = rc2_unmap(cssmKey->KeyHeader.LogicalKeySizeInBits);
	    if (!SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion),
					       rc2version))
		goto loser;
	    newParams = SEC_ASN1EncodeItem (poolp, &algid->parameters, &rc2,
				sec_rc2cbc_parameter_template);
	    PORT_Free(rc2.rc2ParameterVersion.Data);
	    if (newParams == NULL)
		goto loser;
	    break;
	}
	case SEC_OID_RC5_CBC_PAD:
	default:
	    // @@@ Implement rc5 params stuff.
	    goto loser;
	    break;
	}
    }
    else
    {
	// Extract IV from algid.parameters
	// Put IV into algid.parameters
	switch (algtag)
	{
	case SEC_OID_RC4:
	case SEC_OID_DES_EDE3_CBC:
	case SEC_OID_DES_EDE:
	case SEC_OID_DES_CBC:
	case SEC_OID_AES_128_CBC:
	case SEC_OID_AES_192_CBC:
	case SEC_OID_AES_256_CBC:
	case SEC_OID_FORTEZZA_SKIPJACK:
	case SEC_OID_DES_ECB:
	case SEC_OID_AES_128_ECB:
	case SEC_OID_AES_192_ECB:
	case SEC_OID_AES_256_ECB:
	case SEC_OID_DES_OFB:
	case SEC_OID_DES_CFB:
	{
	    CSSM_DATA iv = {};
	    /* Just decode the initVector from an octet string. */
	    rv = SEC_ASN1DecodeItem(NULL, &iv, SEC_OctetStringTemplate, &(algid->parameters));
	    if (rv)
		goto loser;
	    if (initVector.Length != iv.Length) {
		PORT_Free(iv.Data);
		goto loser;
	    }
	    memcpy(initVector.Data, iv.Data, initVector.Length);
	    PORT_Free(iv.Data);
	    break;
	}
	case SEC_OID_RC2_CBC:
	{
	    sec_rc2cbcParameter rc2 = {};
	    unsigned long ulEffectiveBits;

	    rv = SEC_ASN1DecodeItem(NULL, &rc2 ,sec_rc2cbc_parameter_template,
							    &(algid->parameters));
	    if (rv)
		goto loser;

	    if (initVector.Length != rc2.iv.Length) {
		PORT_Free(rc2.iv.Data);
		PORT_Free(rc2.rc2ParameterVersion.Data);
		goto loser;
	    }
	    memcpy(initVector.Data, rc2.iv.Data, initVector.Length);
	    PORT_Free(rc2.iv.Data);

	    ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion);
	    PORT_Free(rc2.rc2ParameterVersion.Data);
	    if (ulEffectiveBits != cssmKey->KeyHeader.LogicalKeySizeInBits)
		goto loser;
	    break;
	}
	case SEC_OID_RC5_CBC_PAD:
	default:
	    // @@@ Implement rc5 params stuff.
	    goto loser;
	    break;
	}
    }

    if (CSSM_CSP_CreateSymmetricContext(cspHandle,
	    algorithm,
	    mode,
	    NULL, /* accessCred */
	    cssmKey,
	    &initVector,
	    padding,
	    NULL, /* reserved */
	    &ciphercc))
	goto loser;

    if (encrypt)
	rv = CSSM_EncryptDataInit(ciphercc);
    else
	rv = CSSM_DecryptDataInit(ciphercc);
    if (rv)
	goto loser;

    cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext));
    if (cc == NULL)
	goto loser;

    cc->cc = ciphercc;
    cc->encrypt = encrypt;

    return cc;
loser:
    if (ciphercc)
	CSSM_DeleteContext(ciphercc);

    return NULL;
}
Ejemplo n.º 17
0
SECStatus
PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
	SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue,
	PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
	SECKEYPrivateKey **privk, void *wincx) 
{
    CK_KEY_TYPE keyType = CKK_RSA;
    SECStatus rv = SECFailure;
    SECKEYRawPrivateKey *lpk = NULL;
    const SEC_ASN1Template *keyTemplate, *paramTemplate;
    void *paramDest = NULL;
    PRArenaPool *arena;

    arena = PORT_NewArena(2048);
    if(!arena) {
	return SECFailure;
    }

    /* need to change this to use RSA/DSA keys */
    lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena,
						  sizeof(SECKEYRawPrivateKey));
    if(lpk == NULL) {
	goto loser;
    }
    lpk->arena = arena;

    switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
	case SEC_OID_PKCS1_RSA_ENCRYPTION:
	    prepare_rsa_priv_key_export_for_asn1(lpk);
	    keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
	    paramTemplate = NULL;
	    paramDest = NULL;
	    lpk->keyType = rsaKey;
	    keyType = CKK_RSA;
	    break;
	case SEC_OID_ANSIX9_DSA_SIGNATURE:
	    prepare_dsa_priv_key_export_for_asn1(lpk);
	    keyTemplate = SECKEY_DSAPrivateKeyExportTemplate;
	    paramTemplate = SECKEY_PQGParamsTemplate;
	    paramDest = &(lpk->u.dsa.params);
	    lpk->keyType = dsaKey;
	    keyType = CKK_DSA;
	    break;
	case SEC_OID_X942_DIFFIE_HELMAN_KEY:
	    if(!publicValue) {
		goto loser;
	    }
	    prepare_dh_priv_key_export_for_asn1(lpk);
	    keyTemplate = SECKEY_DHPrivateKeyExportTemplate;
	    paramTemplate = NULL;
	    paramDest = NULL;
	    lpk->keyType = dhKey;
	    keyType = CKK_DH;
	    break;

	default:
	    keyTemplate   = NULL;
	    paramTemplate = NULL;
	    paramDest     = NULL;
	    break;
    }

    if(!keyTemplate) {
	goto loser;
    }

    /* decode the private key and any algorithm parameters */
    rv = SEC_ASN1DecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
    if(rv != SECSuccess) {
	goto loser;
    }
    if(paramDest && paramTemplate) {
	rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate, 
				 &(pki->algorithm.parameters));
	if(rv != SECSuccess) {
	    goto loser;
	}
    }

    rv = PK11_ImportAndReturnPrivateKey(slot,lpk,nickname,publicValue, isPerm, 
	isPrivate,  keyUsage, privk, wincx);


loser:
    if (lpk!= NULL) {
	PORT_FreeArena(arena, PR_TRUE);
    }

    return rv;
}
Ejemplo n.º 18
0
NS_IMETHODIMP 
nsCRLManager::ImportCrl (PRUint8 *aData, PRUint32 aLength, nsIURI * aURI, PRUint32 aType, PRBool doSilentDonwload, const PRUnichar* crlKey)
{
  nsNSSShutDownPreventionLock locker;
  nsresult rv;
  PRArenaPool *arena = NULL;
  CERTCertificate *caCert;
  SECItem derName = { siBuffer, NULL, 0 };
  SECItem derCrl;
  CERTSignedData sd;
  SECStatus sec_rv;
  CERTSignedCrl *crl;
  nsCAutoString url;
  nsCOMPtr<nsICRLInfo> crlData;
  PRBool importSuccessful;
  PRInt32 errorCode;
  nsString errorMessage;
  
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  if (NS_FAILED(rv)) return rv;
	         
  aURI->GetSpec(url);
  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  if (!arena) {
    goto loser;
  }
  memset(&sd, 0, sizeof(sd));

  derCrl.data = (unsigned char*)aData;
  derCrl.len = aLength;
  sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
  if (sec_rv != SECSuccess) {
    goto loser;
  }

  caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
  if (!caCert) {
    if (aType == SEC_KRL_TYPE){
      goto loser;
    }
  } else {
    sec_rv = SEC_ASN1DecodeItem(arena,
                            &sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 
                            &derCrl);
    if (sec_rv != SECSuccess) {
      goto loser;
    }
    sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
                               nsnull);
    if (sec_rv != SECSuccess) {
      goto loser;
    }
  }
  
  crl = SEC_NewCrl(CERT_GetDefaultCertDB(), const_cast<char*>(url.get()), &derCrl,
                   aType);
  
  if (!crl) {
    goto loser;
  }

  crlData = new nsCRLInfo(crl);
  SSL_ClearSessionCache();
  SEC_DestroyCrl(crl);
  
  importSuccessful = PR_TRUE;
  goto done;

loser:
  importSuccessful = PR_FALSE;
  errorCode = PR_GetError();
  switch (errorCode) {
    case SEC_ERROR_CRL_EXPIRED:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage);
      break;

	case SEC_ERROR_CRL_BAD_SIGNATURE:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage);
      break;

	case SEC_ERROR_CRL_INVALID:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage);
      break;

	case SEC_ERROR_OLD_CRL:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage);
      break;

	case SEC_ERROR_CRL_NOT_YET_VALID:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage);
      break;

    default:
      nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage);
      errorMessage.AppendInt(errorCode,16);
      break;
  }

done:
          
  if(!doSilentDonwload){
    if (!importSuccessful){
      nsString message;
      nsString temp;
      nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
      nsCOMPtr<nsIPrompt> prompter;
      if (wwatch){
        wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
        nssComponent->GetPIPNSSBundleString("CrlImportFailure1x", message);
        message.Append(NS_LITERAL_STRING("\n").get());
        message.Append(errorMessage);
        nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp);
        message.Append(NS_LITERAL_STRING("\n").get());
        message.Append(temp);
     
        if(prompter) {
          nsPSMUITracker tracker;
          if (!tracker.isUIForbidden()) {
            prompter->Alert(0, message.get());
          }
        }
      }
    } else {
      nsCOMPtr<nsICertificateDialogs> certDialogs;
      // Not being able to display the success dialog should not
      // be a fatal error, so don't return a failure code.
      {
        nsPSMUITracker tracker;
        if (tracker.isUIForbidden()) {
          rv = NS_ERROR_NOT_AVAILABLE;
        }
        else {
          rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
            NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID);
        }
      }
      if (NS_SUCCEEDED(rv)) {
        nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
        certDialogs->CrlImportStatusDialog(cxt, crlData);
      }
    }
  } else {
    if(crlKey == nsnull){
      return NS_ERROR_FAILURE;
    }
    nsCOMPtr<nsIPrefService> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
    nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
    if (NS_FAILED(rv)){
      return rv;
    }
    
    nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
    updateErrCntPrefStr.AppendWithConversion(crlKey);
    if(importSuccessful){
      PRUnichar *updateTime;
      nsCAutoString updateTimeStr;
      nsCString updateURL;
      PRInt32 timingTypePref;
      double dayCnt;
      char *dayCntStr;
      nsCAutoString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
      nsCAutoString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
      nsCAutoString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
      nsCAutoString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
      nsCAutoString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
      updateTypePrefStr.AppendWithConversion(crlKey);
      updateTimePrefStr.AppendWithConversion(crlKey);
      updateUrlPrefStr.AppendWithConversion(crlKey);
      updateDayCntPrefStr.AppendWithConversion(crlKey);
      updateFreqCntPrefStr.AppendWithConversion(crlKey);

      pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
      
      //Compute and update the next download instant
      if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){
        pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
      }else{
        pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
      }
      dayCnt = atof(dayCntStr);
      nsMemory::Free(dayCntStr);

      PRBool toBeRescheduled = PR_FALSE;
      if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){
        updateTimeStr.AssignWithConversion(updateTime);
        nsMemory::Free(updateTime);
        pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
        //Now, check if this update time is already in the past. This would
        //imply we have downloaded the same crl, or there is something wrong
        //with the next update date. We will not reschedule this crl in this
        //session anymore - or else, we land into a loop. It would anyway be
        //imported once the browser is restarted.
        PRTime nextTime;
        PR_ParseTimeString(updateTimeStr.get(),PR_TRUE, &nextTime);
        if(LL_CMP(nextTime, > , PR_Now())){
          toBeRescheduled = PR_TRUE;
        }
      }
      
      //Update the url to download from, next time
      crlData->GetLastFetchURL(updateURL);
      pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get());
      
      pref->SetIntPref(updateErrCntPrefStr.get(),0);
      
      if (toBeRescheduled) {
        nsAutoString hashKey(crlKey);
        nssComponent->RemoveCrlFromList(hashKey);
        nssComponent->DefineNextTimer();
      }

    } else{
Ejemplo n.º 19
0
int main(int argc, char **argv)
{
    int verbose=0, force=0;
    int ascii=0, issuerAscii=0;
    char *progName=0;
    PRFileDesc *inFile=0, *issuerCertFile=0;
    SECItem derCert, derIssuerCert;
    PLArenaPool *arena=0;
    CERTSignedData *signedData=0;
    CERTCertificate *cert=0, *issuerCert=0;
    SECKEYPublicKey *rsapubkey=0;
    SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption;
    SECAlgorithmID sha1WithRSAEncryption, rsaEncryption;
    SECItem spk;
    int selfSigned=0;
    int invalid=0;
    char *inFileName = NULL, *issuerCertFileName = NULL;
    PLOptState *optstate;
    PLOptStatus status;
    SECStatus rv;

    PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption));
    PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption));
    PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption));
    PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption));

    progName = strrchr(argv[0], '/');
    progName = progName ? progName+1 : argv[0];

    optstate = PL_CreateOptState(argc, argv, "aAvf");
    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
	switch (optstate->option) {
	  case 'v':
	    verbose = 1;
	    break;

	  case 'f':
	    force = 1;
	    break;

	  case 'a':
	    ascii = 1;
	    break;

	  case 'A':
	    issuerAscii = 1;
	    break;

	  case '\0':
	    if (!inFileName)
		inFileName = PL_strdup(optstate->value);
	    else if (!issuerCertFileName)
		issuerCertFileName = PL_strdup(optstate->value);
	    else
		Usage(progName);
	    break;
	}
    }

    if (!inFileName || !issuerCertFileName || status == PL_OPT_BAD) {
	/* insufficient or excess args */
	Usage(progName);
    }

    inFile = PR_Open(inFileName, PR_RDONLY, 0);
    if (!inFile) {
	fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
	                 progName, inFileName);
	exit(1);
    }

    issuerCertFile = PR_Open(issuerCertFileName, PR_RDONLY, 0);
    if (!issuerCertFile) {
	fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
	                 progName, issuerCertFileName);
	exit(1);
    }

    if (SECU_ReadDERFromFile(&derCert, inFile, ascii, PR_FALSE) != SECSuccess) {
	printf("Couldn't read input certificate as DER binary or base64\n");
	exit(1);
    }

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (arena == 0) {
	fprintf(stderr,"%s: can't allocate scratch arena!", progName);
	exit(1);
    }

    if (issuerCertFile) {
	CERTSignedData *issuerCertSD=0;
	if (SECU_ReadDERFromFile(&derIssuerCert, issuerCertFile, issuerAscii,
	                         PR_FALSE) != SECSuccess) {
	    printf("Couldn't read issuer certificate as DER binary or base64.\n");
	    exit(1);
	}
	issuerCertSD = PORT_ArenaZNew(arena, CERTSignedData);
	if (!issuerCertSD) {
	    fprintf(stderr,"%s: can't allocate issuer signed data!", progName);
	    exit(1);
	}
	rv = SEC_ASN1DecodeItem(arena, issuerCertSD, 
	                        SEC_ASN1_GET(CERT_SignedDataTemplate),
				&derIssuerCert);
	if (rv) {
	    fprintf(stderr, "%s: Issuer cert isn't X509 SIGNED Data?\n",
		    progName);
	    exit(1);
	}
	issuerCert = createEmptyCertificate();
	if (!issuerCert) {
	    printf("%s: can't allocate space for issuer cert.", progName);
	    exit(1);
	}
	rv = SEC_ASN1DecodeItem(arena, issuerCert, 
	                    SEC_ASN1_GET(CERT_CertificateTemplate),
			    &issuerCertSD->data);
	if (rv) {
	    printf("%s: Does not appear to be an X509 Certificate.\n",
		   progName);
	    exit(1);
	}
    }

    signedData =  PORT_ArenaZNew(arena,CERTSignedData);
    if (!signedData) {
	fprintf(stderr,"%s: can't allocate signedData!", progName);
	exit(1);
    }

    rv = SEC_ASN1DecodeItem(arena, signedData, 
                            SEC_ASN1_GET(CERT_SignedDataTemplate), 
			    &derCert);
    if (rv) {
	fprintf(stderr, "%s: Does not appear to be X509 SIGNED Data.\n",
		progName);
	exit(1);
    }

    if (verbose) {
	printf("Decoded ok as X509 SIGNED data.\n");
    }

    cert = createEmptyCertificate();
    if (!cert) {
	fprintf(stderr, "%s: can't allocate cert", progName);
	exit(1);
    }

    rv = SEC_ASN1DecodeItem(arena, cert, 
                        SEC_ASN1_GET(CERT_CertificateTemplate), 
			&signedData->data);
    if (rv) {
	fprintf(stderr, "%s: Does not appear to be an X509 Certificate.\n",
		progName);
	exit(1);
    }


    if (verbose) {
	printf("Decoded ok as an X509 certificate.\n");
    }

    SECU_RegisterDynamicOids();
    rv = SECU_PrintSignedData(stdout, &derCert, "Certificate", 0,
			      (SECU_PPFunc)SECU_PrintCertificate);

    if (rv) {
	fprintf(stderr, "%s: Unable to pretty print cert. Error: %d\n",
		progName, PORT_GetError());
	if (!force) {
	    exit(1);
	}
    }


    /* Do various checks on the cert */

    printf("\n");

    /* Check algorithms */
    rv = SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption,
		       SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL);
    if (rv) {
	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION.\n",
                progName);
	exit(1);
    }

    rv = SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption,
		       SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL);
    if (rv) {
	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION.\n",
                progName);
	exit(1);
    }

    rv = SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption,
		       SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL);
    if (rv) {
	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION.\n",
                progName);
	exit(1);
    }

    rv = SECOID_SetAlgorithmID(arena, &rsaEncryption,
		       SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
    if (rv) {
	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_RSA_ENCRYPTION.\n",
                progName);
	exit(1);
    }

    {
	int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature,
					       &md5WithRSAEncryption) == 0);
	int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature,
					       &md2WithRSAEncryption) == 0);
	int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature,
					       &sha1WithRSAEncryption) == 0);

	if (verbose) {
	    printf("\nDoing algorithm checks.\n");
	}

	if (!(isMD5RSA || isMD2RSA || isSHA1RSA)) {
	    printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.\n");
	} else if (!isMD5RSA) {
	    printf("WARNING: Signature not PKCS1 MD5 with RSA Encryption\n");
	}

	if (SECOID_CompareAlgorithmID(&cert->signature,
				   &signedData->signatureAlgorithm)) {
	    printf("PROBLEM: Algorithm in sig and certInfo don't match.\n");
	}
    }

    if (SECOID_CompareAlgorithmID(&cert->subjectPublicKeyInfo.algorithm,
			       &rsaEncryption)) {
	printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.\n");
    }

    /* Check further public key properties */
    spk = cert->subjectPublicKeyInfo.subjectPublicKey;
    DER_ConvertBitString(&spk);

    if (verbose) {
	printf("\nsubjectPublicKey DER\n");
	rv = DER_PrettyPrint(stdout, &spk, PR_FALSE);
	printf("\n");
    }

    rsapubkey = (SECKEYPublicKey *) 
	             PORT_ArenaZAlloc(arena,sizeof(SECKEYPublicKey));
    if (!rsapubkey) {
	fprintf(stderr, "%s: rsapubkey allocation failed.\n", progName);
	exit(1);
    }

    rv = SEC_ASN1DecodeItem(arena, rsapubkey, 
                            SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), &spk);
    if (rv) {
	printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.\n");
    } else {
	int mlen;
	int pubexp;
	if (verbose) {
	    printf("Decoded RSA Public Key ok.  Doing key checks.\n");
	}
	PORT_Assert(rsapubkey->keyType == rsaKey); /* XXX RSA */
	mlen = checkInteger(&rsapubkey->u.rsa.modulus, "Modulus", verbose);
	printf("INFO: Public Key modulus length in bits: %d\n", mlen);
	if (mlen > MAX_MODULUS) {
	    printf("PROBLEM: Modulus length exceeds %d bits.\n",
		   MAX_MODULUS);
	}
	if (mlen < 512) {
	    printf("WARNING: Short modulus.\n");
	}
	if (mlen != (1 << (ffs(mlen)-1))) {
	    printf("WARNING: Unusual modulus length (not a power of two).\n");
	}
	checkInteger(&rsapubkey->u.rsa.publicExponent, "Public Exponent",
                     verbose);
	pubexp = DER_GetInteger(&rsapubkey->u.rsa.publicExponent);
	if (pubexp != 17 && pubexp != 3 && pubexp != 65537) {
	    printf("WARNING: Public exponent not any of: 3, 17, 65537\n");
	}
    }


    /* Name checks */
    checkName(&cert->issuer, "Issuer Name", verbose);
    checkName(&cert->subject, "Subject Name", verbose);

    if (issuerCert) {
	SECComparison c =
	    CERT_CompareName(&cert->issuer, &issuerCert->subject);
	if (c) {
         printf("PROBLEM: Issuer Name and Subject in Issuing Cert differ\n");
        }
    }

    /* Check if self-signed */
    selfSigned = (CERT_CompareName(&cert->issuer, &cert->subject) == 0);
    if (selfSigned) {
	printf("INFO: Certificate is self signed.\n");
    } else {
	printf("INFO: Certificate is NOT self-signed.\n");
    }


    /* Validity time check */
    if (CERT_CertTimesValid(cert) == SECSuccess) {
	printf("INFO: Inside validity period of certificate.\n");
    } else {
	printf("PROBLEM: Not in validity period of certificate.\n");
	invalid = 1;
    }

    /* Signature check if self-signed */
    if (selfSigned && !invalid) {
	if (rsapubkey->u.rsa.modulus.len) {
	    SECStatus ver;
	    if (verbose) {
		printf("Checking self signature.\n");
	    }
	    ver = OurVerifySignedData(signedData, cert);
	    if (ver != SECSuccess) {
		printf("PROBLEM: Verification of self-signature failed!\n");
	    } else {
		printf("INFO: Self-signature verifies ok.\n");
	    }
	} else {
	    printf("INFO: Not checking signature due to key problems.\n");
	}
    } else if (!selfSigned && !invalid && issuerCert) {
	SECStatus ver;
	ver = OurVerifySignedData(signedData, issuerCert);
	if (ver != SECSuccess) {
	    printf("PROBLEM: Verification of issuer's signature failed!\n");
	} else {
	    printf("INFO: Issuer's signature verifies ok.\n");
	}
    } else {
	printf("INFO: Not checking signature.\n");
    }

    return 0;    
}
Ejemplo n.º 20
0
/*
 * smime_choose_cipher - choose a cipher that works for all the recipients
 *
 * "scert"  - sender's certificate
 * "rcerts" - recipient's certificates
 */
static long
smime_choose_cipher(SecCertificateRef scert, SecCertificateRef *rcerts)
{
    PRArenaPool *poolp;
    long cipher;
    long chosen_cipher;
    int *cipher_abilities;
    int *cipher_votes;
    int weak_mapi;
    int strong_mapi;
    int rcount, mapi, max, i;
#if 1
    // @@@ We Don't support Fortezza yet.
    Boolean scert_is_fortezza  = PR_FALSE;
#else
    Boolean scert_is_fortezza = (scert == NULL) ? PR_FALSE : PK11_FortezzaHasKEA(scert);
#endif

    chosen_cipher = SMIME_RC2_CBC_40;		/* the default, LCD */
    weak_mapi = smime_mapi_by_cipher(chosen_cipher);

    poolp = PORT_NewArena (1024);		/* XXX what is right value? */
    if (poolp == NULL)
	goto done;

    cipher_abilities = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    cipher_votes     = (int *)PORT_ArenaZAlloc(poolp, smime_cipher_map_count * sizeof(int));
    if (cipher_votes == NULL || cipher_abilities == NULL)
	goto done;

    /* If the user has the Fortezza preference turned on, make
     *  that the strong cipher. Otherwise, use triple-DES. */
    strong_mapi = smime_mapi_by_cipher (SMIME_DES_EDE3_168);
    if (scert_is_fortezza) {
	mapi = smime_mapi_by_cipher(SMIME_FORTEZZA);
	if (mapi >= 0 && smime_cipher_map[mapi].enabled)
	    strong_mapi = mapi;
    }

    /* walk all the recipient's certs */
    for (rcount = 0; rcerts[rcount] != NULL; rcount++) {
	CSSM_DATA_PTR profile;
	NSSSMIMECapability **caps;
	int pref;

	/* the first cipher that matches in the user's SMIME profile gets
	 * "smime_cipher_map_count" votes; the next one gets "smime_cipher_map_count" - 1
	 * and so on. If every cipher matches, the last one gets 1 (one) vote */
	pref = smime_cipher_map_count;

	/* find recipient's SMIME profile */
	profile = CERT_FindSMimeProfile(rcerts[rcount]);

	if (profile != NULL && profile->Data != NULL && profile->Length > 0) {
	    /* we have a profile (still DER-encoded) */
	    caps = NULL;
	    /* decode it */
	    if (SEC_ASN1DecodeItem(poolp, &caps, NSSSMIMECapabilitiesTemplate, profile) == SECSuccess &&
		    caps != NULL)
	    {
		/* walk the SMIME capabilities for this recipient */
		for (i = 0; caps[i] != NULL; i++) {
		    cipher = nss_SMIME_FindCipherForSMIMECap(caps[i]);
		    mapi = smime_mapi_by_cipher(cipher);
		    if (mapi >= 0) {
			/* found the cipher */
			cipher_abilities[mapi]++;
			cipher_votes[mapi] += pref;
			--pref;
		    }
		}
	    }
	} else {
	    /* no profile found - so we can only assume that the user can do
	     * the mandatory algorithms which is RC2-40 (weak crypto) and 3DES (strong crypto) */
	    SecPublicKeyRef key;
	    unsigned int pklen_bits;

	    /*
	     * if recipient's public key length is > 512, vote for a strong cipher
	     * please not that the side effect of this is that if only one recipient
	     * has an export-level public key, the strong cipher is disabled.
	     *
	     * XXX This is probably only good for RSA keys.  What I would
	     * really like is a function to just say;  Is the public key in
	     * this cert an export-length key?  Then I would not have to
	     * know things like the value 512, or the kind of key, or what
	     * a subjectPublicKeyInfo is, etc.
	     */
	    key = CERT_ExtractPublicKey(rcerts[rcount]);
	    pklen_bits = 0;
	    if (key != NULL) {
		SecKeyGetStrengthInBits(key, NULL, &pklen_bits);
		SECKEY_DestroyPublicKey (key);
	    }

	    if (pklen_bits > 512) {
		/* cast votes for the strong algorithm */
		cipher_abilities[strong_mapi]++;
		cipher_votes[strong_mapi] += pref;
		pref--;
	    } 

	    /* always cast (possibly less) votes for the weak algorithm */
	    cipher_abilities[weak_mapi]++;
	    cipher_votes[weak_mapi] += pref;
	}
	if (profile != NULL)
	    SECITEM_FreeItem(profile, PR_TRUE);
    }

    /* find cipher that is agreeable by all recipients and that has the most votes */
    max = 0;
    for (mapi = 0; mapi < smime_cipher_map_count; mapi++) {
	/* if not all of the recipients can do this, forget it */
	if (cipher_abilities[mapi] != rcount)
	    continue;
	/* if cipher is not enabled or not allowed by policy, forget it */
	if (!smime_cipher_map[mapi].enabled || !smime_cipher_map[mapi].allowed)
	    continue;
	/* if we're not doing fortezza, but the cipher is fortezza, forget it */
	if (!scert_is_fortezza  && (smime_cipher_map[mapi].cipher == SMIME_FORTEZZA))
	    continue;
	/* now see if this one has more votes than the last best one */
	if (cipher_votes[mapi] >= max) {
	    /* if equal number of votes, prefer the ones further down in the list */
	    /* with the expectation that these are higher rated ciphers */
	    chosen_cipher = smime_cipher_map[mapi].cipher;
	    max = cipher_votes[mapi];
	}
    }
    /* if no common cipher was found, chosen_cipher stays at the default */

done:
    if (poolp != NULL)
	PORT_FreeArena (poolp, PR_FALSE);

    if (smime_keysize_by_cipher(chosen_cipher) < 128) {
        /* you're going to use strong(er) crypto whether you like it or not */
        chosen_cipher = SMIME_DES_EDE3_168;
    }
    return chosen_cipher;
}
/* Generate a mechaism param from a type, and iv. */
SECItem *
PK11_ParamFromAlgid(SECAlgorithmID *algid)
{
    CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL;
    CK_RC2_PARAMS *     rc2_ecb_params = NULL;
    CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL;
    CK_RC5_PARAMS *     rc5_ecb_params = NULL;
    PRArenaPool *       arena          = NULL;
    SECItem *           mech           = NULL;
    SECOidTag           algtag;
    SECStatus           rv;
    CK_MECHANISM_TYPE   type;
    /* initialize these to prevent UMRs in the ASN1 decoder. */
    SECItem             iv  =   {siBuffer, NULL, 0};
    sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} };
    sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0},
                                {siBuffer, NULL, 0}, {siBuffer, NULL, 0} };

    algtag = SECOID_GetAlgorithmTag(algid);
    type = PK11_AlgtagToMechanism(algtag);

    mech = PORT_New(SECItem);
    if (mech == NULL) {
    	return NULL;
    }
    mech->type = siBuffer;
    mech->data = NULL;
    mech->len  = 0;

    arena = PORT_NewArena(1024);
    if (!arena) {
    	goto loser;
    }

    /* handle the complicated cases */
    switch (type) {
    case CKM_RC2_ECB:
        rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template,
							&(algid->parameters));
	if (rv != SECSuccess) { 
	    goto loser;
	}
	rc2_ecb_params = PORT_New(CK_RC2_PARAMS);
	if (rc2_ecb_params == NULL) {
	    goto loser;
	}
	*rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion);
	mech->data = (unsigned char *) rc2_ecb_params;
	mech->len  = sizeof *rc2_ecb_params;
	break;
    case CKM_RC2_CBC:
    case CKM_RC2_CBC_PAD:
        rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template,
							&(algid->parameters));
	if (rv != SECSuccess) { 
	    goto loser;
	}
	rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS);
	if (rc2_cbc_params == NULL) {
	    goto loser;
	}
	mech->data = (unsigned char *) rc2_cbc_params;
	mech->len  = sizeof *rc2_cbc_params;
	rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion);
	if (rc2.iv.len != sizeof rc2_cbc_params->iv) {
	    PORT_SetError(SEC_ERROR_INPUT_LEN);
	    goto loser;
	}
	PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len);
	break;
    case CKM_RC5_ECB:
        rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template,
							&(algid->parameters));
	if (rv != SECSuccess) { 
	    goto loser;
	}
	rc5_ecb_params = PORT_New(CK_RC5_PARAMS);
	if (rc5_ecb_params == NULL) {
	    goto loser;
	}
	rc5_ecb_params->ulRounds   = DER_GetInteger(&rc5.rounds);
	rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8;
	mech->data = (unsigned char *) rc5_ecb_params;
	mech->len = sizeof *rc5_ecb_params;
	break;
    case CKM_RC5_CBC:
    case CKM_RC5_CBC_PAD:
        rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template,
							&(algid->parameters));
	if (rv != SECSuccess) { 
	    goto loser;
	}
	rc5_cbc_params = (CK_RC5_CBC_PARAMS *)
		PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len);
	if (rc5_cbc_params == NULL) {
	    goto loser;
	}
	mech->data = (unsigned char *) rc5_cbc_params;
	mech->len = sizeof *rc5_cbc_params;
	rc5_cbc_params->ulRounds   = DER_GetInteger(&rc5.rounds);
	rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8;
        rc5_cbc_params->pIv        = ((CK_BYTE_PTR)rc5_cbc_params)
						+ sizeof(CK_RC5_CBC_PARAMS);
        rc5_cbc_params->ulIvLen    = rc5.iv.len;
	PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len);
	break;
    case CKM_PBE_MD2_DES_CBC:
    case CKM_PBE_MD5_DES_CBC:
    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
    case CKM_PBE_SHA1_DES2_EDE_CBC:
    case CKM_PBE_SHA1_DES3_EDE_CBC:
    case CKM_PBE_SHA1_RC2_40_CBC:
    case CKM_PBE_SHA1_RC2_128_CBC:
    case CKM_PBE_SHA1_RC4_40:
    case CKM_PBE_SHA1_RC4_128:
    case CKM_PKCS5_PBKD2:
	rv = pbe_PK11AlgidToParam(algid,mech);
	if (rv != SECSuccess) {
	    goto loser;
	}
	break;
    case CKM_RC4:
    case CKM_SEED_ECB:
    case CKM_CAMELLIA_ECB:
    case CKM_AES_ECB:
    case CKM_DES_ECB:
    case CKM_DES3_ECB:
    case CKM_IDEA_ECB:
    case CKM_CDMF_ECB:
    case CKM_CAST_ECB:
    case CKM_CAST3_ECB:
    case CKM_CAST5_ECB:
	break;

    default:
	if (pk11_lookup(type)->iv == 0) {
	    break;
	}
	/* FALL THROUGH */
    case CKM_SEED_CBC:
    case CKM_CAMELLIA_CBC:
    case CKM_AES_CBC:
    case CKM_DES_CBC:
    case CKM_DES3_CBC:
    case CKM_IDEA_CBC:
    case CKM_CDMF_CBC:
    case CKM_CAST_CBC:
    case CKM_CAST3_CBC:
    case CKM_CAST5_CBC:
    case CKM_SEED_CBC_PAD:
    case CKM_CAMELLIA_CBC_PAD:
    case CKM_AES_CBC_PAD:
    case CKM_DES_CBC_PAD:
    case CKM_DES3_CBC_PAD:
    case CKM_IDEA_CBC_PAD:
    case CKM_CDMF_CBC_PAD:
    case CKM_CAST_CBC_PAD:
    case CKM_CAST3_CBC_PAD:
    case CKM_CAST5_CBC_PAD:
    case CKM_SKIPJACK_CBC64:
    case CKM_SKIPJACK_ECB64:
    case CKM_SKIPJACK_OFB64:
    case CKM_SKIPJACK_CFB64:
    case CKM_SKIPJACK_CFB32:
    case CKM_SKIPJACK_CFB16:
    case CKM_SKIPJACK_CFB8:
    case CKM_BATON_ECB128:
    case CKM_BATON_ECB96:
    case CKM_BATON_CBC128:
    case CKM_BATON_COUNTER:
    case CKM_BATON_SHUFFLE:
    case CKM_JUNIPER_ECB128:
    case CKM_JUNIPER_CBC128:
    case CKM_JUNIPER_COUNTER:
    case CKM_JUNIPER_SHUFFLE:
	/* simple cases are simply octet string encoded IVs */
	rv = SEC_ASN1DecodeItem(arena, &iv,
                                SEC_ASN1_GET(SEC_OctetStringTemplate),
                                &(algid->parameters));
	if (rv != SECSuccess || iv.data == NULL) {
	    goto loser;
	}
	/* XXX Should be some IV length sanity check here. */
	mech->data = (unsigned char*)PORT_Alloc(iv.len);
	if (mech->data == NULL) {
	    goto loser;
	}
	PORT_Memcpy(mech->data, iv.data, iv.len);
	mech->len = iv.len;
	break;
    }
    PORT_FreeArena(arena, PR_FALSE);
    return mech;

loser:
    if (arena)
    	PORT_FreeArena(arena, PR_FALSE);
    SECITEM_FreeItem(mech,PR_TRUE);
    return NULL;
}