Example #1
0
OSStatus
SecCmsSignedDataAddDigest(SecArenaPoolRef pool,
				SecCmsSignedDataRef sigd,
				SECOidTag digestalgtag,
				CSSM_DATA_PTR digest)
{
    PRArenaPool *poolp = (PRArenaPool *)pool;
    SECAlgorithmID *digestalg;
    void *mark;

    mark = PORT_ArenaMark(poolp);

    digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
    if (digestalg == NULL)
	goto loser;

    if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
	goto loser;

    if (SecCmsArrayAdd(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess ||
	/* even if digest is NULL, add dummy to have same-size array */
	SecCmsArrayAdd(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess)
    {
	goto loser;
    }

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}
Example #2
0
nsresult
PublicDhKeyToSpki(SECKEYPublicKey* aPubKey,
                  CERTSubjectPublicKeyInfo* aSpki)
{
  SECItem* params = ::SECITEM_AllocItem(aSpki->arena, nullptr, 0);
  if (!params) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  SECItem* rvItem = SEC_ASN1EncodeItem(aSpki->arena, params, aPubKey,
                                       SECKEY_DHParamKeyTemplate);
  if (!rvItem) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  SECStatus rv = SECOID_SetAlgorithmID(aSpki->arena, &aSpki->algorithm,
                                       SEC_OID_X942_DIFFIE_HELMAN_KEY, params);
  if (rv != SECSuccess) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  rvItem = SEC_ASN1EncodeItem(aSpki->arena, &aSpki->subjectPublicKey, aPubKey,
                              SECKEY_DHPublicKeyTemplate);
  if (!rvItem) {
    return NS_ERROR_DOM_OPERATION_ERR;
  }

  // The public value is a BIT_STRING encoded as an INTEGER. After encoding
  // an INT we need to adjust the length to reflect the number of bits.
  aSpki->subjectPublicKey.len <<= 3;

  return NS_OK;
}
Example #3
0
/********************************************************************
 *
 * s i g n _ c e r t
 */
static SECItem *
sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk)
{
    SECStatus rv;

    SECItem der2;
    SECItem * result2;

    void	*dummy;
    SECOidTag alg = SEC_OID_UNKNOWN;

    alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN);
    if (alg == SEC_OID_UNKNOWN) {
	FatalError("Unknown key type");
    }

    rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0);

    if (rv != SECSuccess) {
	PR_fprintf(errorFD, "%s: unable to set signature alg id\n",
	     PROGRAM_NAME);
	errorCount++;
	exit (ERRX);
    }

    der2.len = 0;
    der2.data = NULL;

    dummy = SEC_ASN1EncodeItem
        (cert->arena, &der2, cert, SEC_ASN1_GET(CERT_CertificateTemplate));

    if (rv != SECSuccess) {
	PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME);
	errorCount++;
	exit (ERRX);
    }

    result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem));
    if (result2 == NULL)
	out_of_memory();

    rv = SEC_DerSignData 
        (cert->arena, result2, der2.data, der2.len, privk, alg);

    if (rv != SECSuccess) {
	PR_fprintf(errorFD, "can't sign encoded certificate data\n");
	errorCount++;
	exit (ERRX);
    } else if (verbosity >= 0) {
	PR_fprintf(outputFD, "certificate has been signed\n");
    }

    cert->derCert = *result2;

    return result2;
}
Example #4
0
SECStatus
SEC_DerSignData(PRArenaPool *arena, SECItem *result, 
	unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID)
{
    SECItem it;
    CERTSignedData sd;
    SECStatus rv;

    it.data = 0;

    /* XXX We should probably have some asserts here to make sure the key type
     * and algID match
     */

    if (algID == SEC_OID_UNKNOWN) {
	switch(pk->keyType) {
	  case rsaKey:
	    algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
	    break;
	  case dsaKey:
	    algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
	    break;
	  case ecKey:
	    algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST;
	    break;
	  default:
	    PORT_SetError(SEC_ERROR_INVALID_KEY);
	    return SECFailure;
	}
    }

    /* Sign input buffer */
    rv = SEC_SignData(&it, buf, len, pk, algID);
    if (rv) goto loser;

    /* Fill out SignedData object */
    PORT_Memset(&sd, 0, sizeof(sd));
    sd.data.data = buf;
    sd.data.len = len;
    sd.signature.data = it.data;
    sd.signature.len = it.len << 3;		/* convert to bit string */
    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
    if (rv) goto loser;

    /* DER encode the signed data object */
    rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd);
    /* FALL THROUGH */

  loser:
    PORT_Free(it.data);
    return rv;
}
Example #5
0
OSStatus
SecCmsContentInfoSetContentEncAlg(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo,
				    SECOidTag bulkalgtag, CSSM_DATA_PTR parameters, int keysize)
{
    PLArenaPool *poolp = (PLArenaPool *)pool;
    OSStatus rv;

    rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters);
    if (rv != SECSuccess)
	return SECFailure;
    cinfo->keysize = keysize;
    return SECSuccess;
}
Example #6
0
SECStatus
NSS_CMSContentInfo_SetContentEncAlg(PLArenaPool *poolp, NSSCMSContentInfo *cinfo,
                                    SECOidTag bulkalgtag, SECItem *parameters, int keysize)
{
    SECStatus rv;
    if (cinfo == NULL) {
        return SECFailure;
    }

    rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters);
    if (rv != SECSuccess) {
        return SECFailure;
    }
    cinfo->keysize = keysize;
    return SECSuccess;
}
Example #7
0
int
crypto_cert_get_pub_exp_mod(CryptoCert cert, uint32 * key_len,
		uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len)
{
	SECKEYPublicKey * pubkey;

	SECOidTag tag = SECOID_GetAlgorithmTag(&cert->cert->subjectPublicKeyInfo.algorithm);
	if ((tag == SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION) || (tag == SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE))
	{
		/* For some reason, Microsoft sets the OID of the Public RSA key to
		 the oid for "MD5 with RSA Encryption" instead of "RSA Encryption". */
		SECAlgorithmID org = cert->cert->subjectPublicKeyInfo.algorithm;
		SECStatus s = SECOID_SetAlgorithmID(cert->cert->subjectPublicKeyInfo.arena,
				&cert->cert->subjectPublicKeyInfo.algorithm,
				SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
		check(s, "Error setting temp algo oid");
		pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo);
		SECOID_DestroyAlgorithmID(&cert->cert->subjectPublicKeyInfo.algorithm, False);
		cert->cert->subjectPublicKeyInfo.algorithm = org;
	}
	else
	{
		pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo);
	}
	ASSERT(pubkey);
	ASSERT(pubkey->keyType == rsaKey);

	*key_len = SECKEY_PublicKeyStrength(pubkey);

	size_t l = pubkey->u.rsa.publicExponent.len;
	ASSERT(l <= exp_len);
	memset(exponent, 0, exp_len - l);
	memcpy(exponent + exp_len - l, pubkey->u.rsa.publicExponent.data, l);

	l = pubkey->u.rsa.modulus.len;
	ASSERT(l <= mod_len);
	ASSERT(*key_len <= mod_len);
	memset(modulus, 0, *key_len - l);
	memcpy(modulus + *key_len - l, pubkey->u.rsa.modulus.data, l);

	SECKEY_DestroyPublicKey(pubkey);
	return 0;
}
Example #8
0
SECStatus
NSS_CMSSignedData_AddDigest(PLArenaPool *poolp,
                            NSSCMSSignedData *sigd,
                            SECOidTag digestalgtag,
                            SECItem *digest)
{
    SECAlgorithmID *digestalg;
    void *mark;

    if (!sigd || !poolp) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    mark = PORT_ArenaMark(poolp);

    digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
    if (digestalg == NULL)
        goto loser;

    if (SECOID_SetAlgorithmID(poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
        goto loser;

    if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms),
                         (void *)digestalg) != SECSuccess ||
        /* even if digest is NULL, add dummy to have same-size array */
        NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests),
                         (void *)digest) != SECSuccess) {
        goto loser;
    }

    PORT_ArenaUnmark(poolp, mark);
    return SECSuccess;

loser:
    PORT_ArenaRelease(poolp, mark);
    return SECFailure;
}
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;
}
Example #10
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;    
}
Example #11
0
SECStatus
NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
			SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
			SECItem *pubKey)
{
#if 0 /* not yet done */
    SECOidTag certalgtag;	/* the certificate's encryption algorithm */
    SECOidTag encalgtag;	/* the algorithm used for key exchange/agreement */
    SECStatus rv;
    SECItem *params = NULL;
    int data_len;
    SECStatus err;
    PK11SymKey *tek;
    CERTCertificate *ourCert;
    SECKEYPublicKey *ourPubKey;
    NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid;

    certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
    PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);

    /* We really want to show our KEA tag as the key exchange algorithm tag. */
    encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;

    /* Get the public key of the recipient. */
    publickey = CERT_ExtractPublicKey(cert);
    if (publickey == NULL) goto loser;

    /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
    /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
    if (ourCert == NULL) goto loser;

    arena = PORT_NewArena(1024);
    if (arena == NULL) goto loser;

    /* While we're here, extract the key pair's public key data and copy it into */
    /* the outgoing parameters. */
    /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
    if (ourPubKey == NULL)
    {
	goto loser;
    }
    SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
    SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
    ourPubKey = NULL;

    /* Extract our private key in order to derive the KEA key. */
    ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
    CERT_DestroyCertificate(ourCert); /* we're done with this */
    if (!ourPrivKey) goto loser;

    /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
    if (ukm) {
	ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
	ukm->len = /* XXXX */;
    }

    /* Generate the KEK (key exchange key) according to RFC2631 which we use
     * to wrap the bulk encryption key. */
    kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
			 ukm, NULL,
			 /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
			 CKA_WRAP, 0, wincx);

    SECKEY_DestroyPublicKey(publickey);
    SECKEY_DestroyPrivateKey(ourPrivKey);
    publickey = NULL;
    ourPrivKey = NULL;
    
    if (!kek)
	goto loser;

    /* allocate space for the encrypted CEK (bulk key) */
    encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
    encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;

    if (encKey->data == NULL)
    {
	PK11_FreeSymKey(kek);
	goto loser;
    }


    /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
    /* bulk encryption algorithm */
    switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
    {
    case /* XXXX */CKM_SKIPJACK_CFB8:
	err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
	whichKEA = NSSCMSKEAUsesSkipjack;
	break;
    case /* XXXX */CKM_SKIPJACK_CFB8:
	err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
	whichKEA = NSSCMSKEAUsesSkipjack;
	break;
    default:
	/* XXXX what do we do here? Neither RC2 nor 3DES... */
        err = SECFailure;
        /* set error */
	break;
    }

    PK11_FreeSymKey(kek);	/* we do not need the KEK anymore */
    if (err != SECSuccess)
	goto loser;

    PORT_Assert(whichKEA != NSSCMSKEAInvalid);

    /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
    /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
    params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
    if (params == NULL)
	goto loser;

    /* now set keyEncAlg */
    rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
    if (rv != SECSuccess)
	goto loser;

    /* XXXXXXX this is not right yet */
loser:
    if (arena) {
	PORT_FreeArena(arena, PR_FALSE);
    }
    if (publickey) {
        SECKEY_DestroyPublicKey(publickey);
    }
    if (ourPrivKey) {
        SECKEY_DestroyPrivateKey(ourPrivKey);
    }
#endif
    return SECFailure;
}
Example #12
0
static int
SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert)
{
    SECItem data2sign;
    SECStatus rv;
    char *data;
    SECKEYPrivateKey *privKey;
    SECOidTag algID;
    PLArenaPool *arena;
    CERTSignedData sd;
    SECItem *result;

    if (outFile == NULL || inFile == NULL || cert == NULL)
        return -1;

    /* suck the file in */
    if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
                             PR_FALSE) != SECSuccess)
        return -1;

    privKey = NULL;    
    privKey = PK11_FindKeyByAnyCert(cert, NULL);

    algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1);
    if (algID == SEC_OID_UNKNOWN)
        return -1;
    
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    
    PORT_Memset(&sd, 0, sizeof(CERTSignedData));
    
    rv = SEC_SignData(&(sd.signature), data2sign.data, data2sign.len, privKey, algID);
    if (rv != SECSuccess) {
        fprintf (stderr, "Could not sign.\n");
        return -1;
    }
    sd.signature.len = sd.signature.len << 3;
    
    rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0);
    if (rv != SECSuccess) {
        fprintf (stderr, "Could not set alg id.\n");
        return -1;
    }

    result = SEC_ASN1EncodeItem(arena, NULL, &sd, CERTSignatureDataTemplate);
    SECITEM_FreeItem(&(sd.signature), PR_FALSE);
    
    if (!result) {
        fprintf (stderr, "Could not encode.\n");
        return -1;
    }

    data = PL_Base64Encode((const char*)result->data, result->len, NULL);
    if (!data)
        return -1;
    
    fputs("signature:\n", outFile);
    fputs(data, outFile);
    fputs("\n", outFile);
    ExportPublicKey(outFile, cert);
    
    SECKEY_DestroyPrivateKey(privKey);
    PORT_FreeArena(arena, PR_FALSE);
    
    return 0;
}
/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */
SECStatus
PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, 
				PRArenaPool *arena, SECAlgorithmID *algid) {
    CK_RC2_CBC_PARAMS *rc2_params;
    sec_rc2cbcParameter rc2;
    CK_RC5_CBC_PARAMS *rc5_params;
    sec_rc5cbcParameter rc5;
    CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag);
    SECItem *newParams = NULL;
    SECStatus rv = SECFailure;
    unsigned long rc2version;

    switch (type) {
    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:
	newParams = NULL;
	rv = SECSuccess;
	break;
    case CKM_RC2_ECB:
	break;
    case CKM_RC2_CBC:
    case CKM_RC2_CBC_PAD:
	rc2_params = (CK_RC2_CBC_PARAMS *)param->data;
	rc2version = rc2_unmap(rc2_params->ulEffectiveBits);
	if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion),
					   rc2version) == NULL)
	    break;
	rc2.iv.data = rc2_params->iv;
	rc2.iv.len = sizeof(rc2_params->iv);
	newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2,
                                         sec_rc2cbc_parameter_template);
        PORT_Free(rc2.rc2ParameterVersion.data);
	if (newParams == NULL)
	    break;
	rv = SECSuccess;
	break;

    case CKM_RC5_ECB: /* well not really... */
	break;
    case CKM_RC5_CBC:
    case CKM_RC5_CBC_PAD:
	rc5_params = (CK_RC5_CBC_PARAMS *)param->data;
	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL)
	    break;
	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, 
					rc5_params->ulWordsize*8) == NULL) {
            PORT_Free(rc5.version.data);
	    break;
	}
	if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, 
					rc5_params->ulWordsize*8) == NULL) {
            PORT_Free(rc5.blockSizeInBits.data);
            PORT_Free(rc5.version.data);
	    break;
	}
	rc5.iv.data = rc5_params->pIv;
	rc5.iv.len = rc5_params->ulIvLen;
	newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5,
                                         sec_rc5cbc_parameter_template);
        PORT_Free(rc5.version.data);
        PORT_Free(rc5.blockSizeInBits.data);
        PORT_Free(rc5.rounds.data);
	if (newParams == NULL)
	    break;
	rv = SECSuccess;
	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_DES3_EDE_CBC:
    case CKM_PBE_SHA1_DES2_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:
	return PBE_PK11ParamToAlgid(algTag, param, arena, algid);
    default:
	if (pk11_lookup(type)->iv == 0) {
	    rv = SECSuccess;
	    newParams = NULL;
	    break;
	}
    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_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:
	newParams = SEC_ASN1EncodeItem(NULL,NULL,param,
                                       SEC_ASN1_GET(SEC_OctetStringTemplate) );
	if (newParams == NULL)
	    break;
	rv = SECSuccess;
	break;
    }

    if (rv !=  SECSuccess) {
	if (newParams) SECITEM_FreeItem(newParams,PR_TRUE);
	return rv;
    }

    rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams);
    SECITEM_FreeItem(newParams,PR_TRUE);
    return rv;
}
Example #14
0
/*
 * The caller is responsible for freeing the return value by passing it to
 * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE).
 */
SECKEYPrivateKeyInfo *
PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx)
{
    /* PrivateKeyInfo version (always zero) */
    const unsigned char pkiVersion = 0;
    /* RSAPrivateKey version (always zero) */
    const unsigned char rsaVersion = 0;
    PLArenaPool *arena = NULL;
    SECKEYRawPrivateKey rawKey;
    SECKEYPrivateKeyInfo *pki;
    SECItem *encoded;
    SECStatus rv;

    if (pk->keyType != rsaKey) {
        PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
        goto loser;
    }

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena) {
        goto loser;
    }
    memset(&rawKey, 0, sizeof(rawKey));
    rawKey.keyType = pk->keyType;
    rawKey.u.rsa.version.type = siUnsignedInteger;
    rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
    if (!rawKey.u.rsa.version.data) {
        goto loser;
    }
    rawKey.u.rsa.version.data[0] = rsaVersion;
    rawKey.u.rsa.version.len = 1;

    /* Read the component attributes of the private key */
    prepare_rsa_priv_key_export_for_asn1(&rawKey);
    if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) ||
        !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena,
                       &rawKey.u.rsa.publicExponent) ||
        !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena,
                       &rawKey.u.rsa.privateExponent) ||
        !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) ||
        !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) ||
        !ReadAttribute(pk, CKA_EXPONENT_1, arena,
                       &rawKey.u.rsa.exponent1) ||
        !ReadAttribute(pk, CKA_EXPONENT_2, arena,
                       &rawKey.u.rsa.exponent2) ||
        !ReadAttribute(pk, CKA_COEFFICIENT, arena,
                       &rawKey.u.rsa.coefficient)) {
        goto loser;
    }

    pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo);
    if (!pki) {
        goto loser;
    }
    encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey,
                                 SECKEY_RSAPrivateKeyExportTemplate);
    if (!encoded) {
        goto loser;
    }
    rv = SECOID_SetAlgorithmID(arena, &pki->algorithm,
                               SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
    if (rv != SECSuccess) {
        goto loser;
    }
    pki->version.type = siUnsignedInteger;
    pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1);
    if (!pki->version.data) {
        goto loser;
    }
    pki->version.data[0] = pkiVersion;
    pki->version.len = 1;
    pki->arena = arena;

    return pki;

loser:
    if (arena) {
        PORT_FreeArena(arena, PR_TRUE);
    }
    return NULL;
}
Example #15
0
/*
 * SecCmsSignerInfoSign - sign something
 *
 */
OSStatus
SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
{
    SecCertificateRef cert;
    SecPrivateKeyRef privkey = NULL;
    SECOidTag digestalgtag;
    SECOidTag pubkAlgTag;
    CSSM_DATA signature = { 0 };
    OSStatus rv;
    PLArenaPool *poolp, *tmppoolp = NULL;
    const SECAlgorithmID *algID;
    SECAlgorithmID freeAlgID;
    //CERTSubjectPublicKeyInfo *spki;

    PORT_Assert (digest != NULL);

    poolp = signerinfo->cmsg->poolp;

    switch (signerinfo->signerIdentifier.identifierType) {
    case SecCmsSignerIDIssuerSN:
        privkey = signerinfo->signingKey;
        signerinfo->signingKey = NULL;
        cert = signerinfo->cert;
	if (SecCertificateGetAlgorithmID(cert,&algID)) {
	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	    goto loser;
        }
        break;
    case SecCmsSignerIDSubjectKeyID:
        privkey = signerinfo->signingKey;
        signerinfo->signingKey = NULL;
#if 0
        spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
        SECKEY_DestroyPublicKey(signerinfo->pubKey);
        signerinfo->pubKey = NULL;
        SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
        SECKEY_DestroySubjectPublicKeyInfo(spki);
        algID = &freeAlgID;
#else

#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
	if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) {
#else
	/* TBD: Unify this code. Currently, iOS has an incompatible
	 * SecKeyGetAlgorithmID implementation.  */
	if (true) {
#endif
	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	    goto loser;
	}
	CFRelease(signerinfo->pubKey);
	signerinfo->pubKey = NULL;
#endif
        break;
    default:
        PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE);
        goto loser;
    }
    digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
    /*
     * XXX I think there should be a cert-level interface for this,
     * so that I do not have to know about subjectPublicKeyInfo...
     */
    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
    if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) {
      SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
    }

#if 0
    // @@@ Not yet
    /* Fortezza MISSI have weird signature formats.  
     * Map them to standard DSA formats 
     */
    pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag);
#endif

    if (signerinfo->authAttr != NULL) {
	CSSM_DATA encoded_attrs;

	/* find and fill in the message digest attribute. */
	rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), 
	                       SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
	if (rv != SECSuccess)
	    goto loser;

	if (contentType != NULL) {
	    /* if the caller wants us to, find and fill in the content type attribute. */
	    rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), 
	                    SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
	    if (rv != SECSuccess)
		goto loser;
	}

	if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
	    PORT_SetError(SEC_ERROR_NO_MEMORY);
	    goto loser;
	}

	/*
	 * Before encoding, reorder the attributes so that when they
	 * are encoded, they will be conforming DER, which is required
	 * to have a specific order and that is what must be used for
	 * the hash/signature.  We do this here, rather than building
	 * it into EncodeAttributes, because we do not want to do
	 * such reordering on incoming messages (which also uses
	 * EncodeAttributes) or our old signatures (and other "broken"
	 * implementations) will not verify.  So, we want to guarantee
	 * that we send out good DER encodings of attributes, but not
	 * to expect to receive them.
	 */
	if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess)
	    goto loser;

	encoded_attrs.Data = NULL;
	encoded_attrs.Length = 0;
	if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr), 
	                &encoded_attrs) == NULL)
	    goto loser;

	rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length,
	                  privkey, digestalgtag, pubkAlgTag);
	PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
	tmppoolp = 0;
    } else {
	rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest);
    }
    SECKEY_DestroyPrivateKey(privkey);
    privkey = NULL;

    if (rv != SECSuccess)
	goto loser;

    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) 
          != SECSuccess)
	goto loser;

    SECITEM_FreeItem(&signature, PR_FALSE);

    if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) {
	/*
	 * RFC 3278 section section 2.1.1 states that the signatureAlgorithm 
	 * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey 
	 * as would appear in other forms of signed datas. However Microsoft doesn't 
	 * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, 
	 * MS can't verify - presumably because it takes the digest of the digest 
	 * before feeding it to ECDSA.
	 * We handle this with a preference; default if it's not there is 
	 * "Microsoft compatibility mode". 
	 */
	if(!SecCmsMsEcdsaCompatMode()) {
	    pubkAlgTag = SEC_OID_ECDSA_WithSHA1;
	}
	/* else violating the spec for compatibility */
    }

    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
                              NULL) != SECSuccess)
	goto loser;

    return SECSuccess;

loser:
    if (signature.Length != 0)
	SECITEM_FreeItem (&signature, PR_FALSE);
    if (privkey)
	SECKEY_DestroyPrivateKey(privkey);
    if (tmppoolp)
	PORT_FreeArena(tmppoolp, PR_FALSE);
    return SECFailure;
}

OSStatus
SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray,
				  CFTypeRef policies, SecTrustRef *trustRef)
{
    SecCertificateRef cert;
    CFAbsoluteTime stime;
    OSStatus rv;
    CSSM_DATA_PTR *otherCerts;
    
    if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) {
	dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n");
	signerinfo->verificationStatus = SecCmsVSSigningCertNotFound;
	return SECFailure;
    }

    /*
     * Get and convert the signing time; if available, it will be used
     * both on the cert verification and for importing the sender
     * email profile.
     */
    CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies);
    if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess)
        if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess)
            stime = CFAbsoluteTimeGetCurrent();
    CFReleaseSafe(timeStampPolicies);

    rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts);
    if(rv) {
	return rv;
    }
    rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef);
    dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n",
	    cert, (int)CFGetRetainCount(cert));
    if (rv || !trustRef)
    {
	if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT)
	{
	    /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
	    if (signerinfo->verificationStatus == SecCmsVSGoodSignature)
		signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted;
	}
    }
    /* FIXME isn't this leaking the cert? */
    dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv);
    return rv;
}
Example #16
0
SecCmsSignerInfoRef
nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
{
    void *mark;
    SecCmsSignerInfoRef signerinfo;
    int version;
    PLArenaPool *poolp;

    poolp = cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo));
    if (signerinfo == NULL) {
	PORT_ArenaRelease(poolp, mark);
	return NULL;
    }


    signerinfo->cmsg = cmsg;

    switch(type) {
    case SecCmsSignerIDIssuerSN:
        signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN;
        if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
	    goto loser;
        if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
	    goto loser;
	dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n",
	    (int)CFGetRetainCount(signerinfo->cert));
        break;
    case SecCmsSignerIDSubjectKeyID:
        signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID;
        PORT_Assert(subjKeyID);
        if (!subjKeyID)
            goto loser;
        signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA);
        if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
                             subjKeyID)) {
            goto loser;
        }
        signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
        if (!signerinfo->pubKey)
            goto loser;
        break;
    default:
        goto loser;
    }

    if (!signingKey)
	goto loser;

    signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
    if (!signerinfo->signingKey)
	goto loser;

    /* set version right now */
    version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN;
    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
    if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)
	version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY;
    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);

    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
	goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return signerinfo;

loser:
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}
Example #17
0
static sec_PKCS7CipherObject *
sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo,
						 PK11SymKey *orig_bulkkey)
{
    SECOidTag kind;
    sec_PKCS7CipherObject *encryptobj;
    SEC_PKCS7RecipientInfo **recipientinfos, *ri;
    SEC_PKCS7EncryptedContentInfo *enccinfo;
    SECKEYPublicKey *publickey = NULL;
    SECKEYPrivateKey *ourPrivKey = NULL;
    PK11SymKey  *bulkkey;
    void *mark, *wincx;
    int i;
    PLArenaPool *arena = NULL;

    /* Get the context in case we need it below. */
    wincx = cinfo->pwfn_arg;

    kind = SEC_PKCS7ContentType (cinfo);
    switch (kind) {
      default:
      case SEC_OID_PKCS7_DATA:
      case SEC_OID_PKCS7_DIGESTED_DATA:
      case SEC_OID_PKCS7_SIGNED_DATA:
	recipientinfos = NULL;
	enccinfo = NULL;
	break;
      case SEC_OID_PKCS7_ENCRYPTED_DATA:
	{
	    SEC_PKCS7EncryptedData *encdp;

	    /* To do EncryptedData we *must* be given a bulk key. */
	    PORT_Assert (orig_bulkkey != NULL);
	    if (orig_bulkkey == NULL) {
		/* XXX error? */
		return NULL;
	    }

	    encdp = cinfo->content.encryptedData;
	    recipientinfos = NULL;
	    enccinfo = &(encdp->encContentInfo);
	}
	break;
      case SEC_OID_PKCS7_ENVELOPED_DATA:
	{
	    SEC_PKCS7EnvelopedData *envdp;

	    envdp = cinfo->content.envelopedData;
	    recipientinfos = envdp->recipientInfos;
	    enccinfo = &(envdp->encContentInfo);
	}
	break;
      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:
	{
	    SEC_PKCS7SignedAndEnvelopedData *saedp;

	    saedp = cinfo->content.signedAndEnvelopedData;
	    recipientinfos = saedp->recipientInfos;
	    enccinfo = &(saedp->encContentInfo);
	}
	break;
    }

    if (enccinfo == NULL)
	return NULL;

    bulkkey = orig_bulkkey;
    if (bulkkey == NULL) {
	CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg);
	PK11SlotInfo *slot;


	slot = PK11_GetBestSlot(type,cinfo->pwfn_arg);
	if (slot == NULL) {
	    return NULL;
	}
	bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8,
			      cinfo->pwfn_arg);
	PK11_FreeSlot(slot);
	if (bulkkey == NULL) {
	    return NULL;
	}
    }

    encryptobj = NULL;
    mark = PORT_ArenaMark (cinfo->poolp);

    /*
     * Encrypt the bulk key with the public key of each recipient.
     */
    for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) {
	CERTCertificate *cert;
	SECOidTag certalgtag, encalgtag;
	SECStatus rv;
	int data_len;
	SECItem *params = NULL;

	cert = ri->cert;
	PORT_Assert (cert != NULL);
	if (cert == NULL)
	    continue;

	/*
	 * XXX Want an interface that takes a cert and some data and
	 * fills in an algorithmID and encrypts the data with the public
	 * key from the cert.  Or, give me two interfaces -- one which
	 * gets the algorithm tag from a cert (I should not have to go
	 * down into the subjectPublicKeyInfo myself) and another which
	 * takes a public key and algorithm tag and data and encrypts
	 * the data.  Or something like that.  The point is that all
	 * of the following hardwired RSA stuff should be done elsewhere.
	 */

	certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));

	switch (certalgtag) {
	case SEC_OID_PKCS1_RSA_ENCRYPTION:
	    encalgtag = certalgtag;
	    publickey = CERT_ExtractPublicKey (cert);
	    if (publickey == NULL) goto loser;
		
	    data_len = SECKEY_PublicKeyStrength(publickey);
	    ri->encKey.data = 
	        (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len);
	    ri->encKey.len = data_len;
	    if (ri->encKey.data == NULL) goto loser;

	    rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey,
				bulkkey,&ri->encKey);

	    SECKEY_DestroyPublicKey(publickey);
	    publickey = NULL;
	    if (rv != SECSuccess) goto loser;
	    params = NULL; /* paranoia */
	    break;
	default:
	    PORT_SetError (SEC_ERROR_INVALID_ALGORITHM);
	    goto loser;
	}

	rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, 
			params);
	if (rv != SECSuccess)
	    goto loser;
	if (arena) PORT_FreeArena(arena,PR_FALSE);
	arena = NULL;
    }

    encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey,
					       enccinfo->encalg,
					       &(enccinfo->contentEncAlg));
    if (encryptobj != NULL) {
	PORT_ArenaUnmark (cinfo->poolp, mark);
	mark = NULL;		/* good one; do not want to release */
    }
    /* fallthru */

loser:
    if (arena) {
	PORT_FreeArena(arena, PR_FALSE);
    }
    if (publickey) {
        SECKEY_DestroyPublicKey(publickey);
    }
    if (ourPrivKey) {
        SECKEY_DestroyPrivateKey(ourPrivKey);
    }
    if (mark != NULL) {
	PORT_ArenaRelease (cinfo->poolp, mark);
    }
    if (orig_bulkkey == NULL) {
	if (bulkkey) PK11_FreeSymKey(bulkkey);
    }

    return encryptobj;
}
Example #18
0
NSSCMSSignerInfo *
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
	CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
	SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
{
    void *mark;
    NSSCMSSignerInfo *signerinfo;
    int version;
    PLArenaPool *poolp;

    poolp = cmsg->poolp;

    mark = PORT_ArenaMark(poolp);

    signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
    if (signerinfo == NULL) {
	PORT_ArenaRelease(poolp, mark);
	return NULL;
    }


    signerinfo->cmsg = cmsg;

    switch(type) {
    case NSSCMSSignerID_IssuerSN:
        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
        if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
	    goto loser;
        if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
	    goto loser;
        break;
    case NSSCMSSignerID_SubjectKeyID:
        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
        PORT_Assert(subjKeyID);
        if (!subjKeyID)
            goto loser;

        signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
                         subjKeyID);
        signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
        if (!signerinfo->signingKey)
            goto loser;
        signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
        if (!signerinfo->pubKey)
            goto loser;
        break;
    default:
        goto loser;
    }

    /* set version right now */
    version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
	version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);

    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
	goto loser;

    PORT_ArenaUnmark(poolp, mark);
    return signerinfo;

loser:
    PORT_ArenaRelease(poolp, mark);
    return NULL;
}
Example #19
0
SECStatus
NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, 
                                 SECOidTag bulkalgtag)
{
    CERTCertificate *cert;
    SECOidTag certalgtag;
    SECStatus rv = SECSuccess;
    NSSCMSRecipientEncryptedKey *rek;
    NSSCMSOriginatorIdentifierOrKey *oiok;
    CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
    PLArenaPool *poolp;
    NSSCMSKeyTransRecipientInfoEx *extra = NULL;
    PRBool usesSubjKeyID;

    poolp = ri->cmsg->poolp;
    cert = ri->cert;
    usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
    if (cert) {
	spki = &cert->subjectPublicKeyInfo;
    } else if (usesSubjKeyID) {
	extra = &ri->ri.keyTransRecipientInfoEx;
	/* sanity check */
	PORT_Assert(extra->pubKey);
	if (!extra->pubKey) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return SECFailure;
	}
	spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
    } else {
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return SECFailure;
    }

    /* XXX set ri->recipientInfoType to the proper value here */
    /* or should we look if it's been set already ? */

    certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
    switch (certalgtag) {
    case SEC_OID_PKCS1_RSA_ENCRYPTION:
	/* wrap the symkey */
	if (cert) {
	    rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, 
	                         &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	} else if (usesSubjKeyID) {
	    PORT_Assert(extra != NULL);
	    rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
	                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	}

	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
	break;
    case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
	rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
	if (rek == NULL) {
	    rv = SECFailure;
	    break;
	}

	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
	PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);

	/* see RFC2630 12.3.1.1 */
	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
				    SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
	    rv = SECFailure;
	    break;
	}

	/* this will generate a key pair, compute the shared secret, */
	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
	rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey,
					&rek->encKey,
					&ri->ri.keyAgreeRecipientInfo.ukm,
					&ri->ri.keyAgreeRecipientInfo.keyEncAlg,
					&oiok->id.originatorPublicKey.publicKey);

	break;
    default:
	/* other algorithms not supported yet */
	/* NOTE that we do not support any KEK algorithm */
	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	rv = SECFailure;
    }
    if (freeSpki)
	SECKEY_DestroySubjectPublicKeyInfo(freeSpki);

    return rv;
}
Example #20
0
OSStatus
SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, 
                                 SECOidTag bulkalgtag)
{
    SecCertificateRef cert;
    SECOidTag certalgtag;
    OSStatus rv = SECSuccess;
#if 0
    CSSM_DATA_PTR params = NULL;
#endif /* 0 */
    SecCmsRecipientEncryptedKey *rek;
    SecCmsOriginatorIdentifierOrKey *oiok;
    const SECAlgorithmID *algid;
    PLArenaPool *poolp;
    SecCmsKeyTransRecipientInfoEx *extra = NULL;
    Boolean usesSubjKeyID;
    uint8 nullData[2] = {SEC_ASN1_NULL, 0};
    SECItem nullItem;
    SecCmsKeyAgreeRecipientInfo *kari;
    
    poolp = ri->cmsg->poolp;
    cert = ri->cert;
    usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
    if (cert) {
	rv = SecCertificateGetAlgorithmID(cert,&algid);
	if (rv)
	    return SECFailure;
	certalgtag = SECOID_GetAlgorithmTag(algid);
    } else if (usesSubjKeyID) {
	extra = &ri->ri.keyTransRecipientInfoEx;
	/* sanity check */
	PORT_Assert(extra->pubKey);
	if (!extra->pubKey) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return SECFailure;
	}
	rv = SecKeyGetAlgorithmID(extra->pubKey,&algid);
	if (rv)
	    return SECFailure;
	certalgtag = SECOID_GetAlgorithmTag(algid);
    } else {
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return SECFailure;
    }

    /* XXX set ri->recipientInfoType to the proper value here */
    /* or should we look if it's been set already ? */

    certalgtag = SECOID_GetAlgorithmTag(algid);
    switch (certalgtag) {
    case SEC_OID_PKCS1_RSA_ENCRYPTION:
	/* wrap the symkey */
	if (cert) {
	    rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, 
	                         &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	} else if (usesSubjKeyID) {
	    PORT_Assert(extra != NULL);
	    rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey,
	                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	}

	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
	break;
#if 0
    case SEC_OID_MISSI_KEA_DSS_OLD:
    case SEC_OID_MISSI_KEA_DSS:
    case SEC_OID_MISSI_KEA:
	rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey,
					bulkalgtag,
					&ri->ri.keyTransRecipientInfo.encKey,
					&params, ri->cmsg->pwfn_arg);
	if (rv != SECSuccess)
	    break;

	/* here, we DO need to pass the params to the wrap function because, with
	 * RSA, there is no funny stuff going on with generation of IV vectors or so */
	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);
	break;
    case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
	rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
	if (rek == NULL) {
	    rv = SECFailure;
	    break;
	}

	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
	PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);

	/* see RFC2630 12.3.1.1 */
	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
				    SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
	    rv = SECFailure;
	    break;
	}

	/* this will generate a key pair, compute the shared secret, */
	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
	rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey,
					&rek->encKey,
					&ri->ri.keyAgreeRecipientInfo.ukm,
					&ri->ri.keyAgreeRecipientInfo.keyEncAlg,
					&oiok->id.originatorPublicKey.publicKey);

	break;
#endif /* 0 */

    case SEC_OID_EC_PUBLIC_KEY:
	/* These were set up in nss_cmsrecipientinfo_create() */
	kari = &ri->ri.keyAgreeRecipientInfo;
	rek = kari->recipientEncryptedKeys[0];
	if (rek == NULL) {
	    rv = SECFailure;
	    break;
	}

	oiok = &(kari->originatorIdentifierOrKey);
	PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);

	/* 
	 * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to 
	 * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one
	 * explicitly instead of mucking up the login in SECOID_SetAlgorithmID().
	 */
	nullItem.Data = nullData;
	nullItem.Length = 2;
	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
				    SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) {
	    rv = SECFailure;
	    break;
	}

	/* this will generate a key pair, compute the shared secret, */
	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
	rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey,
					&rek->encKey,
					&kari->ukm,
					&kari->keyEncAlg,
					&oiok->id.originatorPublicKey.publicKey);
	/* this is a BIT STRING */
	oiok->id.originatorPublicKey.publicKey.Length <<= 3;
	break;

    default:
	/* other algorithms not supported yet */
	/* NOTE that we do not support any KEK algorithm */
	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	rv = SECFailure;
	break;
    }
#if 0
    if (freeSpki)
	SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
#endif

    return rv;
}
Example #21
0
static SECItem *
sec_CreateRSAPSSParameters(PLArenaPool *arena,
                           SECItem *result,
                           SECOidTag hashAlgTag,
                           const SECItem *params,
                           const SECKEYPrivateKey *key)
{
    SECKEYRSAPSSParams pssParams;
    int modBytes, hashLength;
    unsigned long saltLength;
    PRBool defaultSHA1 = PR_FALSE;
    SECStatus rv;

    if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
        return NULL;
    }

    PORT_Memset(&pssParams, 0, sizeof(pssParams));

    if (params && params->data) {
        /* The parameters field should either be empty or contain
         * valid RSA-PSS parameters */
        PORT_Assert(!(params->len == 2 &&
                      params->data[0] == SEC_ASN1_NULL &&
                      params->data[1] == 0));
        rv = SEC_QuickDERDecodeItem(arena, &pssParams,
                                    SECKEY_RSAPSSParamsTemplate,
                                    params);
        if (rv != SECSuccess) {
            return NULL;
        }
        defaultSHA1 = PR_TRUE;
    }

    if (pssParams.trailerField.data) {
        unsigned long trailerField;

        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField,
                                   &trailerField);
        if (rv != SECSuccess) {
            return NULL;
        }
        if (trailerField != 1) {
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
            return NULL;
        }
    }

    modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key);

    /* Determine the hash algorithm to use, based on hashAlgTag and
     * pssParams.hashAlg; there are four cases */
    if (hashAlgTag != SEC_OID_UNKNOWN) {
        SECOidTag tag = SEC_OID_UNKNOWN;

        if (pssParams.hashAlg) {
            tag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
        } else if (defaultSHA1) {
            tag = SEC_OID_SHA1;
        }

        if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) {
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
            return NULL;
        }
    } else if (hashAlgTag == SEC_OID_UNKNOWN) {
        if (pssParams.hashAlg) {
            hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
        } else if (defaultSHA1) {
            hashAlgTag = SEC_OID_SHA1;
        } else {
            /* Find a suitable hash algorithm based on the NIST recommendation */
            if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */
                hashAlgTag = SEC_OID_SHA256;
            } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */
                hashAlgTag = SEC_OID_SHA384;
            } else {
                hashAlgTag = SEC_OID_SHA512;
            }
        }
    }

    if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 &&
        hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 &&
        hashAlgTag != SEC_OID_SHA512) {
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
        return NULL;
    }

    /* Now that the hash algorithm is decided, check if it matches the
     * existing parameters if any */
    if (pssParams.maskAlg) {
        SECAlgorithmID maskHashAlg;

        if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            return NULL;
        }

        if (pssParams.maskAlg->parameters.data == NULL) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            return NULL;
        }

        PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg));
        rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg,
                                    SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
                                    &pssParams.maskAlg->parameters);
        if (rv != SECSuccess) {
            return NULL;
        }

        /* Following the recommendation in RFC 4055, assume the hash
         * algorithm identical to pssParam.hashAlg */
        if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            return NULL;
        }
    } else if (defaultSHA1) {
        if (hashAlgTag != SEC_OID_SHA1) {
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
            return NULL;
        }
    }

    hashLength = HASH_ResultLenByOidTag(hashAlgTag);

    if (pssParams.saltLength.data) {
        rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength,
                                   &saltLength);
        if (rv != SECSuccess) {
            return NULL;
        }

        /* The specified salt length is too long */
        if (saltLength > modBytes - hashLength - 2) {
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
            return NULL;
        }
    } else if (defaultSHA1) {
        saltLength = 20;
    }

    /* Fill in the parameters */
    if (pssParams.hashAlg) {
        if (hashAlgTag == SEC_OID_SHA1) {
            /* Omit hashAlg if the the algorithm is SHA-1 (default) */
            pssParams.hashAlg = NULL;
        }
    } else {
        if (hashAlgTag != SEC_OID_SHA1) {
            pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
            if (!pssParams.hashAlg) {
                return NULL;
            }
            rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag,
                                       NULL);
            if (rv != SECSuccess) {
                return NULL;
            }
        }
    }

    if (pssParams.maskAlg) {
        if (hashAlgTag == SEC_OID_SHA1) {
            /* Omit maskAlg if the the algorithm is SHA-1 (default) */
            pssParams.maskAlg = NULL;
        }
    } else {
        if (hashAlgTag != SEC_OID_SHA1) {
            SECItem *hashAlgItem;

            PORT_Assert(pssParams.hashAlg != NULL);

            hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg,
                                             SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
            if (!hashAlgItem) {
                return NULL;
            }
            pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID));
            if (!pssParams.maskAlg) {
                return NULL;
            }
            rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg,
                                       SEC_OID_PKCS1_MGF1, hashAlgItem);
            if (rv != SECSuccess) {
                return NULL;
            }
        }
    }

    if (pssParams.saltLength.data) {
        if (saltLength == 20) {
            /* Omit the salt length if it is the default */
            pssParams.saltLength.data = NULL;
        }
    } else {
        /* Find a suitable length from the hash algorithm and modulus bits */
        saltLength = PR_MIN(hashLength, modBytes - hashLength - 2);

        if (saltLength != 20 &&
            !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) {
            return NULL;
        }
    }

    if (pssParams.trailerField.data) {
        /* Omit trailerField if the value is 1 (default) */
        pssParams.trailerField.data = NULL;
    }

    return SEC_ASN1EncodeItem(arena, result,
                              &pssParams, SECKEY_RSAPSSParamsTemplate);
}
Example #22
0
OSStatus
SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, 
                                 SECOidTag bulkalgtag)
{
    SecCertificateRef cert;
    SECOidTag certalgtag;
    OSStatus rv = SECSuccess;
#if 0
    SecAsn1Item * params = NULL;
    SecCmsRecipientEncryptedKey *rek;
    SecCmsOriginatorIdentifierOrKey *oiok;
#endif /* 0 */
    const SECAlgorithmID *algid;
    PLArenaPool *poolp;
    SecCmsKeyTransRecipientInfoEx *extra = NULL;
    Boolean usesSubjKeyID;

    poolp = ri->envelopedData->contentInfo.cmsg->poolp;
    cert = ri->cert;
    usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
    if (cert) {
#if USE_CDSA_CRYPTO
	rv = SecCertificateGetAlgorithmID(cert,&algid);
	if (rv)
	    return SECFailure;
#else
        SECAlgorithmID freeAlgID;
        const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert);
        freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data;
        freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length;
        freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data;
        freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length;
        algid = &freeAlgID;
#endif
    } else if (usesSubjKeyID) {
	extra = &ri->ri.keyTransRecipientInfoEx;
	/* sanity check */
	PORT_Assert(extra->pubKey);
	if (!extra->pubKey) {
	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
	    return SECFailure;
	}
#if USE_CDSA_CRYPTO
	rv = SecKeyGetAlgorithmID(extra->pubKey,&algid);
	if (rv)
#endif
	    return SECFailure;
	certalgtag = SECOID_GetAlgorithmTag(algid);
    } else {
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
	return SECFailure;
    }

    /* XXX set ri->recipientInfoType to the proper value here */
    /* or should we look if it's been set already ? */

    certalgtag = SECOID_GetAlgorithmTag(algid);
    switch (certalgtag) {
    case SEC_OID_PKCS1_RSA_ENCRYPTION:
	/* wrap the symkey */
	if (cert) {
	    rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, 
	                         &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	} else if (usesSubjKeyID) {
	    PORT_Assert(extra != NULL);
	    rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey,
	                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
 	    if (rv != SECSuccess)
		break;
	}

	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
	break;
#if 0
    case SEC_OID_MISSI_KEA_DSS_OLD:
    case SEC_OID_MISSI_KEA_DSS:
    case SEC_OID_MISSI_KEA:
	rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey,
					bulkalgtag,
					&ri->ri.keyTransRecipientInfo.encKey,
					&params, ri->cmsg->pwfn_arg);
	if (rv != SECSuccess)
	    break;

	/* here, we DO need to pass the params to the wrap function because, with
	 * RSA, there is no funny stuff going on with generation of IV vectors or so */
	rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params);
	break;
    case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
	rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
	if (rek == NULL) {
	    rv = SECFailure;
	    break;
	}

	oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
	PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey);

	/* see RFC2630 12.3.1.1 */
	if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
				    SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
	    rv = SECFailure;
	    break;
	}

	/* this will generate a key pair, compute the shared secret, */
	/* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
	/* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
	rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey,
					&rek->encKey,
					&ri->ri.keyAgreeRecipientInfo.ukm,
					&ri->ri.keyAgreeRecipientInfo.keyEncAlg,
					&oiok->id.originatorPublicKey.publicKey);

	break;
#endif /* 0 */
    default:
	/* other algorithms not supported yet */
	/* NOTE that we do not support any KEK algorithm */
	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	rv = SECFailure;
	break;
    }
#if 0
    if (freeSpki)
	SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
#endif

    return rv;
}
  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();
  }
Example #24
0
SGNDigestInfo *
SGN_CreateDigestInfo(SECOidTag algorithm, const unsigned char *sig,
                     unsigned len)
{
    SGNDigestInfo *di;
    SECStatus rv;
    PLArenaPool *arena;
    SECItem *null_param;
    SECItem dummy_value;

    switch (algorithm) {
    case SEC_OID_MD2:
    case SEC_OID_MD5:
    case SEC_OID_SHA1:
    case SEC_OID_SHA224:
    case SEC_OID_SHA256:
    case SEC_OID_SHA384:
    case SEC_OID_SHA512:
        break;
    default:
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
        return NULL;
    }

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (arena == NULL) {
        return NULL;
    }

    di = (SGNDigestInfo *) PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
    if (di == NULL) {
        PORT_FreeArena(arena, PR_FALSE);
        return NULL;
    }

    di->arena = arena;

    /*
     * PKCS #1 specifies that the AlgorithmID must have a NULL parameter
     * (as opposed to no parameter at all).
     */
    dummy_value.data = NULL;
    dummy_value.len = 0;
    null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate);
    if (null_param == NULL) {
        goto loser;
    }

    rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm,
                               null_param);

    SECITEM_FreeItem(null_param, PR_TRUE);

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

    di->digest.data = (unsigned char *) PORT_ArenaAlloc(arena, len);
    if (di->digest.data == NULL) {
        goto loser;
    }

    di->digest.len = len;
    PORT_Memcpy(di->digest.data, sig, len);
    return di;

loser:
    SGN_DestroyDigestInfo(di);
    return NULL;
}
Example #25
0
CRMFEncryptedValue *
crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey,
        SECKEYPublicKey *inCAKey,
        CRMFEncryptedValue *destValue)
{
    SECItem wrappedPrivKey, wrappedSymKey;
    SECItem encodedParam, *dummy;
    SECStatus rv;
    CK_MECHANISM_TYPE pubMechType, symKeyType;
    unsigned char *wrappedSymKeyBits;
    unsigned char *wrappedPrivKeyBits;
    SECItem *iv = NULL;
    SECOidTag tag;
    PK11SymKey *symKey;
    PK11SlotInfo *slot;
    SECAlgorithmID *symmAlg;
    CRMFEncryptedValue *myEncrValue = NULL;

    encodedParam.data = NULL;
    wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN);
    if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) {
        goto loser;
    }
    if (destValue == NULL) {
        myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue);
        if (destValue == NULL) {
            goto loser;
        }
    }

    pubMechType = crmf_get_mechanism_from_public_key(inCAKey);
    if (pubMechType == CKM_INVALID_MECHANISM) {
        /* XXX I should probably do something here for non-RSA
         *     keys that are in certs. (ie DSA)
         * XXX or at least SET AN ERROR CODE.
         */
        goto loser;
    }
    slot = inPrivKey->pkcs11Slot;
    PORT_Assert(slot != NULL);
    symKeyType = crmf_get_best_privkey_wrap_mechanism(slot);
    symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL);
    if (symKey == NULL) {
        goto loser;
    }

    wrappedSymKey.data = wrappedSymKeyBits;
    wrappedSymKey.len = MAX_WRAPPED_KEY_LEN;
    rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    /* Make the length of the result a Bit String length. */
    wrappedSymKey.len <<= 3;

    wrappedPrivKey.data = wrappedPrivKeyBits;
    wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN;
    iv = crmf_get_iv(symKeyType);
    rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv,
                          &wrappedPrivKey, NULL);
    PK11_FreeSymKey(symKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    /* Make the length of the result a Bit String length. */
    wrappedPrivKey.len <<= 3;
    rv = crmf_make_bitstring_copy(NULL,
                                  &destValue->encValue,
                                  &wrappedPrivKey);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = crmf_make_bitstring_copy(NULL,
                                  &destValue->encSymmKey,
                                  &wrappedSymKey);
    if (rv != SECSuccess) {
        goto loser;
    }
    destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID);
    if (symmAlg == NULL) {
        goto loser;
    }

    dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv,
                               SEC_ASN1_GET(SEC_OctetStringTemplate));
    if (dummy != &encodedParam) {
        SECITEM_FreeItem(dummy, PR_TRUE);
        goto loser;
    }

    symKeyType = crmf_get_non_pad_mechanism(symKeyType);
    tag = PK11_MechanismToAlgtag(symKeyType);
    rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam);
    if (rv != SECSuccess) {
        goto loser;
    }
    SECITEM_FreeItem(&encodedParam, PR_FALSE);
    PORT_Free(wrappedPrivKeyBits);
    PORT_Free(wrappedSymKeyBits);
    SECITEM_FreeItem(iv, PR_TRUE);
    return destValue;
loser:
    if (iv != NULL) {
        SECITEM_FreeItem(iv, PR_TRUE);
    }
    if (myEncrValue != NULL) {
        crmf_destroy_encrypted_value(myEncrValue, PR_TRUE);
    }
    if (wrappedSymKeyBits != NULL) {
        PORT_Free(wrappedSymKeyBits);
    }
    if (wrappedPrivKeyBits != NULL) {
        PORT_Free(wrappedPrivKeyBits);
    }
    if (encodedParam.data != NULL) {
        SECITEM_FreeItem(&encodedParam, PR_FALSE);
    }
    return NULL;
}
Example #26
0
/*
 * NSS_CMSSignerInfo_Sign - sign something
 *
 */
SECStatus
NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, 
                       SECItem *contentType)
{
    CERTCertificate *cert;
    SECKEYPrivateKey *privkey = NULL;
    SECOidTag digestalgtag;
    SECOidTag pubkAlgTag;
    SECItem signature = { 0 };
    SECStatus rv;
    PLArenaPool *poolp, *tmppoolp = NULL;
    SECAlgorithmID *algID, freeAlgID;
    CERTSubjectPublicKeyInfo *spki;

    PORT_Assert (digest != NULL);

    poolp = signerinfo->cmsg->poolp;

    switch (signerinfo->signerIdentifier.identifierType) {
    case NSSCMSSignerID_IssuerSN:
        cert = signerinfo->cert;

        privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
        if (privkey == NULL)
	    goto loser;
        algID = &cert->subjectPublicKeyInfo.algorithm;
        break;
    case NSSCMSSignerID_SubjectKeyID:
        privkey = signerinfo->signingKey;
        signerinfo->signingKey = NULL;
        spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
        SECKEY_DestroyPublicKey(signerinfo->pubKey);
        signerinfo->pubKey = NULL;
        SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
        SECKEY_DestroySubjectPublicKeyInfo(spki); 
        algID = &freeAlgID;
        break;
    default:
        goto loser;
    }
    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
    /*
     * XXX I think there should be a cert-level interface for this,
     * so that I do not have to know about subjectPublicKeyInfo...
     */
    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
      SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
    }

    if (signerinfo->authAttr != NULL) {
	SECOidTag signAlgTag;
	SECItem encoded_attrs;

	/* find and fill in the message digest attribute. */
	rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
	                       SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
	if (rv != SECSuccess)
	    goto loser;

	if (contentType != NULL) {
	    /* if the caller wants us to, find and fill in the content type attribute. */
	    rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
	                    SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
	    if (rv != SECSuccess)
		goto loser;
	}

	if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
	    PORT_SetError(SEC_ERROR_NO_MEMORY);
	    goto loser;
	}

	/*
	 * Before encoding, reorder the attributes so that when they
	 * are encoded, they will be conforming DER, which is required
	 * to have a specific order and that is what must be used for
	 * the hash/signature.  We do this here, rather than building
	 * it into EncodeAttributes, because we do not want to do
	 * such reordering on incoming messages (which also uses
	 * EncodeAttributes) or our old signatures (and other "broken"
	 * implementations) will not verify.  So, we want to guarantee
	 * that we send out good DER encodings of attributes, but not
	 * to expect to receive them.
	 */
	if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
	    goto loser;

	encoded_attrs.data = NULL;
	encoded_attrs.len = 0;
	if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), 
	                &encoded_attrs) == NULL)
	    goto loser;

	signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType, 
                                                     digestalgtag);
	if (signAlgTag == SEC_OID_UNKNOWN) {
	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
	    goto loser;
	}

	rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, 
	                  privkey, signAlgTag);
	PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
	tmppoolp = 0;
    } else {
	rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
    }
    SECKEY_DestroyPrivateKey(privkey);
    privkey = NULL;

    if (rv != SECSuccess)
	goto loser;

    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) 
          != SECSuccess)
	goto loser;

    SECITEM_FreeItem(&signature, PR_FALSE);

    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
                              NULL) != SECSuccess)
	goto loser;

    return SECSuccess;

loser:
    if (signature.len != 0)
	SECITEM_FreeItem (&signature, PR_FALSE);
    if (privkey)
	SECKEY_DestroyPrivateKey(privkey);
    if (tmppoolp)
	PORT_FreeArena(tmppoolp, PR_FALSE);
    return SECFailure;
}
Example #27
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();
}