Esempio n. 1
0
/**
 * @brief Initialise a context for decrypting arbitrary data using the given key.
 * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
 *       *ctx is not NULL, *ctx must point at a previously created structure.
 * @param ctx The block context returned, see note.
 * @param blockSize The block size of the cipher.
 * @param iv Optional initialisation vector. If the buffer pointed to is NULL,
 *           an IV will be created at random, in space allocated from the pool.
 *           If the buffer is not NULL, the IV in the buffer will be used.
 * @param key The key structure.
 * @param p The pool to use.
 * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
 *         Returns APR_EINIT if the backend failed to initialise the context. Returns
 *         APR_ENOTIMPL if not implemented.
 */
static apr_status_t crypto_block_decrypt_init(apr_crypto_block_t **ctx,
        apr_size_t *blockSize, const unsigned char *iv,
        const apr_crypto_key_t *key, apr_pool_t *p)
{
    PRErrorCode perr;
    SECItem * secParam;
    apr_crypto_block_t *block = *ctx;
    if (!block) {
        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
    }
    if (!block) {
        return APR_ENOMEM;
    }
    block->f = key->f;
    block->pool = p;
    block->provider = key->provider;

    apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
            apr_pool_cleanup_null);

    if (key->ivSize) {
        SECItem ivItem;
        if (iv == NULL) {
            return APR_ENOIV; /* Cannot initialise without an IV */
        }
        ivItem.data = (unsigned char*) iv;
        ivItem.len = key->ivSize;
        secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
    }
    else {
        secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
    }
    block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
    block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT,
            key->symKey, secParam);

    /* did an error occur? */
    perr = PORT_GetError();
    if (perr || !block->ctx) {
        key->f->result->rc = perr;
        key->f->result->msg = PR_ErrorToName(perr);
        return APR_EINIT;
    }

    if (blockSize) {
        *blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
    }

    return APR_SUCCESS;

}
Esempio n. 2
0
/*
 * NSS_CMSCipherContext_StartDecrypt - create a cipher context to do decryption
 * based on the given bulk encryption key and algorithm identifier (which 
 * may include an iv).
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function below (for starting up encryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
NSSCMSCipherContext *
NSS_CMSCipherContext_StartDecrypt(PK11SymKey *key, SECAlgorithmID *algid)
{
    NSSCMSCipherContext *cc;
    void *ciphercx;
    CK_MECHANISM_TYPE cryptoMechType;
    PK11SlotInfo *slot;
    SECOidTag algtag;
    SECItem *param = NULL;

    algtag = SECOID_GetAlgorithmTag(algid);

    /* set param and mechanism */
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	SECItem *pwitem;

	pwitem = PK11_GetSymKeyUserData(key);
	if (!pwitem) 
	    return NULL;

	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
	if (cryptoMechType == CKM_INVALID_MECHANISM) {
	    SECITEM_FreeItem(param,PR_TRUE);
	    return NULL;
	}

    } else {
	cryptoMechType = PK11_AlgtagToMechanism(algtag);
	if ((param = PK11_ParamFromAlgid(algid)) == NULL)
	    return NULL;
    }

    cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
    if (cc == NULL) {
	SECITEM_FreeItem(param,PR_TRUE);
	return NULL;
    }

    /* figure out pad and block sizes */
    cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
    slot = PK11_GetSlotFromKey(key);
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
    PK11_FreeSlot(slot);

    /* create PK11 cipher context */
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, 
					  key, param);
    SECITEM_FreeItem(param, PR_TRUE);
    if (ciphercx == NULL) {
	PORT_Free (cc);
	return NULL;
    }

    cc->cx = ciphercx;
    cc->doit =  (nss_cms_cipher_function) PK11_CipherOp;
    cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext;
    cc->encrypt = PR_FALSE;
    cc->pending_count = 0;

    return cc;
}
Esempio n. 3
0
/*
 * NSS_CMSCipherContext_StartEncrypt - create a cipher object to do encryption,
 * based on the given bulk encryption key and algorithm tag.  Fill in the 
 * algorithm identifier (which may include an iv) appropriately.
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function above (for starting up decryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
NSSCMSCipherContext *
NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid)
{
    NSSCMSCipherContext *cc;
    void *ciphercx;
    SECStatus rv;
    CK_MECHANISM_TYPE cryptoMechType;
    PK11SlotInfo *slot;
    SECItem *param = NULL;
    PRBool needToEncodeAlgid = PR_FALSE;
    SECOidTag algtag = SECOID_GetAlgorithmTag(algid);

    /* set param and mechanism */
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	SECItem *pwitem;

	pwitem = PK11_GetSymKeyUserData(key);
	if (!pwitem) 
	    return NULL;

	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
	if (cryptoMechType == CKM_INVALID_MECHANISM) {
	    SECITEM_FreeItem(param,PR_TRUE);
	    return NULL;
	}
    } else {
	cryptoMechType = PK11_AlgtagToMechanism(algtag);
	if ((param = PK11_GenerateNewParam(cryptoMechType, key)) == NULL)
	    return NULL;
	needToEncodeAlgid = PR_TRUE;
    }

    cc = (NSSCMSCipherContext *)PORT_ZAlloc(sizeof(NSSCMSCipherContext));
    if (cc == NULL) {
	goto loser;
    }

    /* now find pad and block sizes for our mechanism */
    cc->pad_size = PK11_GetBlockSize(cryptoMechType, param);
    slot = PK11_GetSlotFromKey(key);
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
    PK11_FreeSlot(slot);

    /* and here we go, creating a PK11 cipher context */
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, 
					  key, param);
    if (ciphercx == NULL) {
	PORT_Free(cc);
	cc = NULL;
	goto loser;
    }

    /*
     * These are placed after the CreateContextBySymKey() because some
     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
     * Don't move it from here.
     * XXX is that right? the purpose of this is to get the correct algid
     *     containing the IVs etc. for encoding. this means we need to set this up
     *     BEFORE encoding the algid in the contentInfo, right?
     */
    if (needToEncodeAlgid) {
	rv = PK11_ParamToAlgid(algtag, param, poolp, algid);
	if(rv != SECSuccess) {
	    PORT_Free(cc);
	    cc = NULL;
	    goto loser;
	}
    }

    cc->cx = ciphercx;
    cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
    cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
    cc->encrypt = PR_TRUE;
    cc->pending_count = 0;

loser:
    SECITEM_FreeItem(param, PR_TRUE);

    return cc;
}
Esempio n. 4
0
/*
 * Create a cipher object to do decryption,  based on the given bulk
 * encryption key and algorithm identifier (which may include an iv).
 *
 * XXX This interface, or one similar, would be really nice available
 * in general...  I tried to keep the pkcs7-specific stuff (mostly
 * having to do with padding) out of here.
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function below (for starting up encryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
sec_PKCS7CipherObject *
sec_PKCS7CreateDecryptObject (PK11SymKey *key, SECAlgorithmID *algid)
{
    sec_PKCS7CipherObject *result;
    SECOidTag algtag;
    void *ciphercx;
    CK_MECHANISM_TYPE cryptoMechType;
    PK11SlotInfo *slot;
    SECItem *param = NULL;

    result = (struct sec_pkcs7_cipher_object*)
      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
    if (result == NULL)
	return NULL;

    ciphercx = NULL;
    algtag = SECOID_GetAlgorithmTag (algid);

    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	SECItem *pwitem;

	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
	if (!pwitem) {
	    PORT_Free(result);
	    return NULL;
	}

	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
	if (cryptoMechType == CKM_INVALID_MECHANISM) {
	    PORT_Free(result);
	    SECITEM_FreeItem(param,PR_TRUE);
	    return NULL;
	}
    } else {
	cryptoMechType = PK11_AlgtagToMechanism(algtag);
	param = PK11_ParamFromAlgid(algid);
	if (param == NULL) {
	    PORT_Free(result);
	    return NULL;
	}
    }

    result->pad_size = PK11_GetBlockSize(cryptoMechType, param);
    slot = PK11_GetSlotFromKey(key);
    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
    PK11_FreeSlot(slot);
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, 
					  key, param);
    SECITEM_FreeItem(param,PR_TRUE);
    if (ciphercx == NULL) {
	PORT_Free (result);
	return NULL;
    }

    result->cx = ciphercx;
    result->doit =  (sec_pkcs7_cipher_function) PK11_CipherOp;
    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
    result->encrypt = PR_FALSE;
    result->pending_count = 0;

    return result;
}
Esempio n. 5
0
/*
 * Create a cipher object to do encryption, based on the given bulk
 * encryption key and algorithm tag.  Fill in the algorithm identifier
 * (which may include an iv) appropriately.
 *
 * XXX This interface, or one similar, would be really nice available
 * in general...  I tried to keep the pkcs7-specific stuff (mostly
 * having to do with padding) out of here.
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function above (for starting up decryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
sec_PKCS7CipherObject *
sec_PKCS7CreateEncryptObject (PRArenaPool *poolp, PK11SymKey *key,
			      SECOidTag algtag, SECAlgorithmID *algid)
{
    sec_PKCS7CipherObject *result;
    void *ciphercx;
    SECStatus rv;
    CK_MECHANISM_TYPE cryptoMechType;
    PK11SlotInfo *slot;
    SECItem *param = NULL;
    PRBool needToEncodeAlgid = PR_FALSE;

    result = (struct sec_pkcs7_cipher_object*)
	      PORT_ZAlloc (sizeof(struct sec_pkcs7_cipher_object));
    if (result == NULL)
	return NULL;

    ciphercx = NULL;
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	SECItem *pwitem;

	pwitem = (SECItem *)PK11_GetSymKeyUserData(key);
	if (!pwitem) {
	    PORT_Free(result);
	    return NULL;
	}

	cryptoMechType = PK11_GetPBECryptoMechanism(algid, &param, pwitem);
	if (cryptoMechType == CKM_INVALID_MECHANISM) {
	    PORT_Free(result);
	    SECITEM_FreeItem(param,PR_TRUE);
	    return NULL;
	}
    } else {
	cryptoMechType = PK11_AlgtagToMechanism(algtag);
	param = PK11_GenerateNewParam(cryptoMechType, key);
	if (param == NULL) {
	    PORT_Free(result);
	    return NULL;
	}
	needToEncodeAlgid = PR_TRUE;
    }

    result->pad_size = PK11_GetBlockSize(cryptoMechType,param);
    slot = PK11_GetSlotFromKey(key);
    result->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : result->pad_size;
    PK11_FreeSlot(slot);
    ciphercx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, 
    					  key, param);
    if (ciphercx == NULL) {
	PORT_Free (result);
        SECITEM_FreeItem(param,PR_TRUE);
	return NULL;
    }

    /*
     * These are placed after the CreateContextBySymKey() because some
     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
     * Don't move it from here.
     */
    if (needToEncodeAlgid) {
	rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
	if(rv != SECSuccess) {
	    PORT_Free (result);
            SECITEM_FreeItem(param,PR_TRUE);
	    return NULL;
	}
    }
    SECITEM_FreeItem(param,PR_TRUE);

    result->cx = ciphercx;
    result->doit = (sec_pkcs7_cipher_function) PK11_CipherOp;
    result->destroy = (sec_pkcs7_cipher_destroy) PK11_DestroyContext;
    result->encrypt = PR_TRUE;
    result->pending_count = 0;

    return result;
}
Esempio n. 6
0
/*
 * CreatePk11PinStore
 */
int
CreatePk11PinStore(Pk11PinStore **out, const char *tokenName, const char *pin)
{
    int err = PIN_SUCCESS;
    Pk11PinStore *store;

    do {

        store = (Pk11PinStore*)malloc(sizeof(Pk11PinStore));
        if (store == 0) { err = PIN_NOMEMORY; break; }

        /* Low-level init */
        store->key = 0;
        store->params = 0;
        store->crypt = 0;

        /* Use the tokenName to find a PKCS11 slot */
        store->slot = PK11_FindSlotByName((char *)tokenName);
        if (store->slot == 0) { err = PIN_NOSUCHTOKEN; break; }

        /* Check the password/PIN.  This allows access to the token */
        {
            SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin);

            if (rv == SECSuccess)
                ;
            else if (rv == SECWouldBlock)
            {
                /* NSS returns a blocking error when the pin is wrong */
                err = PIN_INCORRECTPW;
                break;
            }
            else
            {
                err = PIN_SYSTEMERROR;
                break;
            }
        }

        /* Find the mechanism that this token can do */
        {
            const mech_item *tp;

            store->mech = 0;
            for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++)
            {
                if (PK11_DoesMechanism(store->slot, tp->type))
                {
                    store->mech = (mech_item *)tp;
                    break;
                }
            }
            /* Default to a mechanism (probably on the internal token */
            if (store->mech == 0) {
                store->mech = &dflt_mech;
            }
        }

        /* Generate a key and parameters to do the encryption */
#if NSS_VMAJOR >= 3 && (NSS_VMINOR <= 9 || (NSS_VMINOR <= 10 && NSS_VPATCH == 0))
        store->key = PK11_KeyGen(store->slot, store->mech->type,
                       0, 0, 0);
#else
        store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type,
                     NULL, 0, NULL, CKF_ENCRYPT|CKF_DECRYPT, PR_FALSE, NULL);
#endif
        if (store->key == 0)
        {
            /* PR_SetError(xxx); */
            err = PIN_SYSTEMERROR;
            break;
        }

        store->params = PK11_GenerateNewParam(store->mech->type, store->key);
        if (store->params == 0)
        {
            err = PIN_SYSTEMERROR;
            break;
        }

        /* Compute the size of the encrypted data including necessary padding */
        {
            int blocksize = PK11_GetBlockSize(store->mech->type, 0);

            store->length = strlen(pin)+1;

            /* Compute padded size - 0 means stream cipher */
            if (blocksize != 0)
            {
                store->length += blocksize - (store->length % blocksize);
            }

            store->crypt = (unsigned char *)malloc(store->length);
            if (!store->crypt) { err = PIN_NOMEMORY; break; }
        }

        /* Encrypt */
        {
            unsigned char *plain;
            PK11Context *ctx;
            SECStatus rv;
            int outLen;

            plain = (unsigned char *)malloc(store->length);
            if (!plain) { err = PIN_NOMEMORY; break; }

            /* Pad with 0 bytes */
            memset(plain, 0, store->length);
            strcpy((char *)plain, pin);

            ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT,
                    store->key, store->params);
            if (!ctx) { err = PIN_SYSTEMERROR; break; }

            do {
                rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length,
                       plain, store->length);
                if (rv) break;

                rv = PK11_Finalize(ctx);
            } while(0);

            PK11_DestroyContext(ctx, PR_TRUE);
            memset(plain, 0, store->length);
            free(plain);

            if (rv) err = PIN_SYSTEMERROR;
        }
    } while(0);

    if (err)
    {
        DestroyPk11PinStore(store);
        store = 0;
    }

    *out = store;
    return err;
}
Esempio n. 7
0
/* the content of an encrypted data content info is decrypted.
 * it is assumed that for encrypted data, that the data has already
 * been set and is in the "encContent" field of the content info.
 *
 * cinfo is the content info to decrypt
 *
 * key is the key with which to perform the decryption.  if the
 *     algorithm is a password based encryption algorithm, the
 *     key is actually a password which will be processed per
 *     PKCS #5.
 * 
 * in the event of an error, SECFailure is returned.  SECSuccess
 * indicates a success.
 */
SECStatus 
SEC_PKCS7DecryptContents(PRArenaPool *poolp,
			 SEC_PKCS7ContentInfo *cinfo,
			 SECItem *key,
			 void *wincx)
{
    SECAlgorithmID *algid = NULL;
    SECStatus rv = SECFailure;
    SECItem *result = NULL, *dest, *src;
    void *mark;

    PK11SymKey *eKey = NULL;
    PK11SlotInfo *slot = NULL;
    CK_MECHANISM_TYPE cryptoMechType;
    void *cx;
    SECItem *c_param = NULL;
    int bs;

    if((cinfo == NULL) || (key == NULL))
	return SECFailure;

    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
	return SECFailure;

    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
    if(algid == NULL)
	return SECFailure;

    if(poolp == NULL)
	poolp = cinfo->poolp;

    mark = PORT_ArenaMark(poolp);
    
    src = &cinfo->content.encryptedData->encContentInfo.encContent;
    dest = &cinfo->content.encryptedData->encContentInfo.plainContent;
    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
    dest->len = (src->len + 64);
    if(dest->data == NULL) {
	rv = SECFailure;
	goto loser;
    }

    slot = PK11_GetInternalKeySlot();
    if(slot == NULL) {
	rv = SECFailure;
	goto loser;
    }

    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
    if(eKey == NULL) {
	rv = SECFailure;
	goto loser;
    }
    
    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
    if (cryptoMechType == CKM_INVALID_MECHANISM) {
	rv = SECFailure;
	goto loser;
    }

    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT,
		    		    eKey, c_param);
    if(cx == NULL) {
	rv = SECFailure;
	goto loser;
    }

    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
		       (int)(src->len + 64), src->data, (int)src->len);
    PK11_DestroyContext((PK11Context *)cx, PR_TRUE);

    bs = PK11_GetBlockSize(cryptoMechType, c_param);
    if(bs) {
	/* check for proper badding in block algorithms.  this assumes
	 * RC2 cbc or a DES cbc variant.  and the padding is thus defined
	 */
	if(((int)dest->data[dest->len-1] <= bs) && 
	   ((int)dest->data[dest->len-1] > 0)) {
	    dest->len -= (int)dest->data[dest->len-1];
	} else {
	    rv = SECFailure;
	    /* set an error ? */
	}
    } 

loser:
    /* let success fall through */
    if(result != NULL)
	SECITEM_ZfreeItem(result, PR_TRUE);

    if(rv == SECFailure)
	PORT_ArenaRelease(poolp, mark);
    else
	PORT_ArenaUnmark(poolp, mark);

    if(eKey != NULL)
	PK11_FreeSymKey(eKey);

    if(slot != NULL)
	PK11_FreeSlot(slot);

    if(c_param != NULL) 
	SECITEM_ZfreeItem(c_param, PR_TRUE);
	
    return rv;
}
Esempio n. 8
0
/* the content of an encrypted data content info is encrypted.
 * it is assumed that for encrypted data, that the data has already
 * been set and is in the "plainContent" field of the content info.
 *
 * cinfo is the content info to encrypt
 *
 * key is the key with which to perform the encryption.  if the
 *     algorithm is a password based encryption algorithm, the
 *     key is actually a password which will be processed per
 *     PKCS #5.
 * 
 * in the event of an error, SECFailure is returned.  SECSuccess
 * indicates a success.
 */
SECStatus 
SEC_PKCS7EncryptContents(PRArenaPool *poolp,
			 SEC_PKCS7ContentInfo *cinfo,
			 SECItem *key,
			 void *wincx)
{
    SECAlgorithmID *algid 	= NULL;
    SECItem *       result 	= NULL;
    SECItem *       src;
    SECItem *       dest;
    SECItem *       blocked_data = NULL;
    void *          mark;
    void *          cx;
    PK11SymKey *    eKey 	= NULL;
    PK11SlotInfo *  slot 	= NULL;

    CK_MECHANISM_TYPE cryptoMechType;
    int             bs;
    SECStatus       rv 		= SECFailure;
    SECItem         *c_param = NULL;

    if((cinfo == NULL) || (key == NULL))
	return SECFailure;

    if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA)
	return SECFailure;

    algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo);	
    if(algid == NULL)
	return SECFailure;

    if(poolp == NULL)
	poolp = cinfo->poolp;

    mark = PORT_ArenaMark(poolp);
    
    src = &cinfo->content.encryptedData->encContentInfo.plainContent;
    dest = &cinfo->content.encryptedData->encContentInfo.encContent;
    dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64));
    dest->len = (src->len + 64);
    if(dest->data == NULL) {
	rv = SECFailure;
	goto loser;
    }

    slot = PK11_GetInternalKeySlot();
    if(slot == NULL) {
	rv = SECFailure;
	goto loser;
    }

    eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx);
    if(eKey == NULL) {
	rv = SECFailure;
	goto loser;
    }
    
    cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key);
    if (cryptoMechType == CKM_INVALID_MECHANISM) {
	rv = SECFailure;
	goto loser;
    }

    /* block according to PKCS 8 */
    bs = PK11_GetBlockSize(cryptoMechType, c_param);
    rv = SECSuccess;
    if(bs) {
	char pad_char;
	pad_char = (char)(bs - (src->len % bs));
	if(src->len % bs) {
	    rv = SECSuccess;
	    blocked_data = PK11_BlockData(src, bs);
	    if(blocked_data) {
		PORT_Memset((blocked_data->data + blocked_data->len 
			    - (int)pad_char), 
			    pad_char, (int)pad_char);
	    } else {
		rv = SECFailure;
		goto loser;
	    }
	} else {
	    blocked_data = SECITEM_DupItem(src);
	    if(blocked_data) {
		blocked_data->data = (unsigned char*)PORT_Realloc(
						  blocked_data->data,
						  blocked_data->len + bs);
		if(blocked_data->data) {
		    blocked_data->len += bs;
		    PORT_Memset((blocked_data->data + src->len), (char)bs, bs);
		} else {
		    rv = SECFailure;
		    goto loser;
		}
	    } else {
		rv = SECFailure;
		goto loser;
	    }
	 }
    } else {
	blocked_data = SECITEM_DupItem(src);
	if(!blocked_data) {
	    rv = SECFailure;
	    goto loser;
	}
    }

    cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT,
		    		    eKey, c_param);
    if(cx == NULL) {
	rv = SECFailure;
	goto loser;
    }

    rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), 
		       (int)(src->len + 64), blocked_data->data, 
		       (int)blocked_data->len);
    PK11_DestroyContext((PK11Context*)cx, PR_TRUE);

loser:
    /* let success fall through */
    if(blocked_data != NULL)
	SECITEM_ZfreeItem(blocked_data, PR_TRUE);

    if(result != NULL)
	SECITEM_ZfreeItem(result, PR_TRUE);

    if(rv == SECFailure)
	PORT_ArenaRelease(poolp, mark);
    else 
	PORT_ArenaUnmark(poolp, mark);

    if(eKey != NULL)
	PK11_FreeSymKey(eKey);

    if(slot != NULL)
	PK11_FreeSlot(slot);

    if(c_param != NULL) 
	SECITEM_ZfreeItem(c_param, PR_TRUE);
	
    return rv;
}
Esempio n. 9
0
/*
 * SecCmsCipherContextStartEncrypt - create a cipher object to do encryption,
 * based on the given bulk encryption key and algorithm tag.  Fill in the algorithm
 * identifier (which may include an iv) appropriately.
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function above (for starting up decryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
SecCmsCipherContext *
SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid)
{
    return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE);
#if 0
    SecCmsCipherContext *cc;
    void *ciphercx;
    CSSM_DATA *param;
    OSStatus rv;
    CK_MECHANISM_TYPE mechanism;
    PK11SlotInfo *slot;
    PRBool needToEncodeAlgid = PR_FALSE;
    SECOidTag algtag = SECOID_GetAlgorithmTag(algid);

    /* set param and mechanism */
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	CK_MECHANISM pbeMech, cryptoMech;
	CSSM_DATA *pbeParams;
	SEC_PKCS5KeyAndPassword *keyPwd;

	PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
	PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));

	/* HACK ALERT!
	 * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword *
	 */
	keyPwd = (SEC_PKCS5KeyAndPassword *)key;
	key = keyPwd->key;

	/* find correct PK11 mechanism and parameters to initialize pbeMech */
	pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
	pbeParams = PK11_ParamFromAlgid(algid);
	if (!pbeParams)
	    return NULL;
	pbeMech.pParameter = pbeParams->Data;
	pbeMech.ulParameterLen = pbeParams->Length;

	/* now map pbeMech to cryptoMech */
	if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem,
						  PR_FALSE) != CKR_OK) { 
	    SECITEM_ZfreeItem(pbeParams, PR_TRUE);
	    return NULL;
	}
	SECITEM_ZfreeItem(pbeParams, PR_TRUE);

	/* and use it to initialize param & mechanism */
	if ((param = (CSSM_DATA *)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL)
	    return NULL;

	param->Data = (unsigned char *)cryptoMech.pParameter;
	param->Length = cryptoMech.ulParameterLen;
	mechanism = cryptoMech.mechanism;
    } else {
	mechanism = PK11_AlgtagToMechanism(algtag);
	if ((param = PK11_GenerateNewParam(mechanism, key)) == NULL)
	    return NULL;
	needToEncodeAlgid = PR_TRUE;
    }

    cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext));
    if (cc == NULL)
	return NULL;

    /* now find pad and block sizes for our mechanism */
    cc->pad_size = PK11_GetBlockSize(mechanism,param);
    slot = PK11_GetSlotFromKey(key);
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
    PK11_FreeSlot(slot);

    /* and here we go, creating a PK11 cipher context */
    ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, key, param);
    if (ciphercx == NULL) {
	PORT_Free(cc);
	cc = NULL;
	goto loser;
    }

    /*
     * These are placed after the CreateContextBySymKey() because some
     * mechanisms have to generate their IVs from their card (i.e. FORTEZZA).
     * Don't move it from here.
     * XXX is that right? the purpose of this is to get the correct algid
     *     containing the IVs etc. for encoding. this means we need to set this up
     *     BEFORE encoding the algid in the contentInfo, right?
     */
    if (needToEncodeAlgid) {
	rv = PK11_ParamToAlgid(algtag, param, poolp, algid);
	if(rv != SECSuccess) {
	    PORT_Free(cc);
	    cc = NULL;
	    goto loser;
	}
    }

    cc->cx = ciphercx;
    cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
    cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
    cc->encrypt = PR_TRUE;
    cc->pending_count = 0;

loser:
    SECITEM_FreeItem(param, PR_TRUE);

    return cc;
#endif
}
Esempio n. 10
0
/*
 * SecCmsCipherContextStartDecrypt - create a cipher context to do decryption
 * based on the given bulk * encryption key and algorithm identifier (which may include an iv).
 *
 * XXX Once both are working, it might be nice to combine this and the
 * function below (for starting up encryption) into one routine, and just
 * have two simple cover functions which call it. 
 */
SecCmsCipherContext *
SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid)
{
    return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE);
#if 0
    SecCmsCipherContext *cc;
    void *ciphercx;
    CK_MECHANISM_TYPE mechanism;
    CSSM_DATA *param;
    PK11SlotInfo *slot;
    SECOidTag algtag;

    algtag = SECOID_GetAlgorithmTag(algid);

    /* set param and mechanism */
    if (SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
	CK_MECHANISM pbeMech, cryptoMech;
	CSSM_DATA *pbeParams;
	SEC_PKCS5KeyAndPassword *keyPwd;

	PORT_Memset(&pbeMech, 0, sizeof(CK_MECHANISM));
	PORT_Memset(&cryptoMech, 0, sizeof(CK_MECHANISM));

	/* HACK ALERT!
	 * in this case, key is not actually a SecSymmetricKeyRef, but a SEC_PKCS5KeyAndPassword *
	 */
	keyPwd = (SEC_PKCS5KeyAndPassword *)key;
	key = keyPwd->key;

	/* find correct PK11 mechanism and parameters to initialize pbeMech */
	pbeMech.mechanism = PK11_AlgtagToMechanism(algtag);
	pbeParams = PK11_ParamFromAlgid(algid);
	if (!pbeParams)
	    return NULL;
	pbeMech.pParameter = pbeParams->Data;
	pbeMech.ulParameterLen = pbeParams->Length;

	/* now map pbeMech to cryptoMech */
	if (PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, keyPwd->pwitem,
						  PR_FALSE) != CKR_OK) { 
	    SECITEM_ZfreeItem(pbeParams, PR_TRUE);
	    return NULL;
	}
	SECITEM_ZfreeItem(pbeParams, PR_TRUE);

	/* and use it to initialize param & mechanism */
	if ((param = (CSSM_DATA *)PORT_ZAlloc(sizeof(CSSM_DATA))) == NULL)
	     return NULL;

	param->Data = (unsigned char *)cryptoMech.pParameter;
	param->Length = cryptoMech.ulParameterLen;
	mechanism = cryptoMech.mechanism;
    } else {
	mechanism = PK11_AlgtagToMechanism(algtag);
	if ((param = PK11_ParamFromAlgid(algid)) == NULL)
	    return NULL;
    }

    cc = (SecCmsCipherContext *)PORT_ZAlloc(sizeof(SecCmsCipherContext));
    if (cc == NULL) {
	SECITEM_FreeItem(param,PR_TRUE);
	return NULL;
    }

    /* figure out pad and block sizes */
    cc->pad_size = PK11_GetBlockSize(mechanism, param);
    slot = PK11_GetSlotFromKey(key);
    cc->block_size = PK11_IsHW(slot) ? BLOCK_SIZE : cc->pad_size;
    PK11_FreeSlot(slot);

    /* create PK11 cipher context */
    ciphercx = PK11_CreateContextBySymKey(mechanism, CKA_DECRYPT, key, param);
    SECITEM_FreeItem(param, PR_TRUE);
    if (ciphercx == NULL) {
	PORT_Free (cc);
	return NULL;
    }

    cc->cx = ciphercx;
    cc->doit =  (nss_cms_cipher_function) PK11_CipherOp;
    cc->destroy = (nss_cms_cipher_destroy) PK11_DestroyContext;
    cc->encrypt = PR_FALSE;
    cc->pending_count = 0;

    return cc;
#endif
}
Esempio n. 11
0
/**
 * @brief Initialise a context for encrypting arbitrary data using the given key.
 * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
 *       *ctx is not NULL, *ctx must point at a previously created structure.
 * @param ctx The block context returned, see note.
 * @param iv Optional initialisation vector. If the buffer pointed to is NULL,
 *           an IV will be created at random, in space allocated from the pool.
 *           If the buffer pointed to is not NULL, the IV in the buffer will be
 *           used.
 * @param key The key structure.
 * @param blockSize The block size of the cipher.
 * @param p The pool to use.
 * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
 *         Returns APR_EINIT if the backend failed to initialise the context. Returns
 *         APR_ENOTIMPL if not implemented.
 */
static apr_status_t crypto_block_encrypt_init(apr_crypto_block_t **ctx,
        const unsigned char **iv, const apr_crypto_key_t *key,
        apr_size_t *blockSize, apr_pool_t *p)
{
    PRErrorCode perr;
    SECItem * secParam;
    SECItem ivItem;
    unsigned char * usedIv;
    apr_crypto_block_t *block = *ctx;
    if (!block) {
        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
    }
    if (!block) {
        return APR_ENOMEM;
    }
    block->f = key->f;
    block->pool = p;
    block->provider = key->provider;

    apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
            apr_pool_cleanup_null);

    if (key->ivSize) {
        if (iv == NULL) {
            return APR_ENOIV;
        }
        if (*iv == NULL) {
            SECStatus s;
            usedIv = apr_pcalloc(p, key->ivSize);
            if (!usedIv) {
                return APR_ENOMEM;
            }
            apr_crypto_clear(p, usedIv, key->ivSize);
            s = PK11_GenerateRandom(usedIv, key->ivSize);
            if (s != SECSuccess) {
                return APR_ENOIV;
            }
            *iv = usedIv;
        }
        else {
            usedIv = (unsigned char *) *iv;
        }
        ivItem.data = usedIv;
        ivItem.len = key->ivSize;
        secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
    }
    else {
        secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
    }
    block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
    block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT,
            key->symKey, secParam);

    /* did an error occur? */
    perr = PORT_GetError();
    if (perr || !block->ctx) {
        key->f->result->rc = perr;
        key->f->result->msg = PR_ErrorToName(perr);
        return APR_EINIT;
    }

    if (blockSize) {
        *blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
    }

    return APR_SUCCESS;

}
/*
 * SVRCORE_CreatePk11PinStore
 */
SVRCOREError
SVRCORE_CreatePk11PinStore(
  SVRCOREPk11PinStore **out,
  const char *tokenName, const char *pin)
{
  SVRCOREError err;
  SVRCOREPk11PinStore *store;

  do {
    err = SVRCORE_Success;

    store = (SVRCOREPk11PinStore*)malloc(sizeof *store);
    if (store == 0) { err = SVRCORE_NoMemory_Error; break; }

    /* Low-level init */
    store->slot = 0;
    store->key = 0;
    store->params = 0;
    store->crypt = 0;

    /* Use the tokenName to find a PKCS11 slot */
    store->slot = PK11_FindSlotByName((char *)tokenName);
    if (store->slot == 0) { err = SVRCORE_NoSuchToken_Error; break; }

    /* Check the password/PIN.  This allows access to the token */
    {
      SECStatus rv = PK11_CheckUserPassword(store->slot, (char *)pin);

      if (rv == SECSuccess)
        ;
      else if (rv == SECWouldBlock)
      {
        err = SVRCORE_IncorrectPassword_Error;
        break;
      }
      else
      {
        err = SVRCORE_System_Error;
        break;
      }
    }

    /* Find the mechanism that this token can do */
    {
      const mech_item *tp;

      store->mech = 0;
      for(tp = table;tp < &table[MECH_TABLE_SIZE];tp++)
      {
        if (PK11_DoesMechanism(store->slot, tp->type))
        {
          store->mech = tp;
          break;
        }
      }
      /* Default to a mechanism (probably on the internal token */
      if (store->mech == 0)
        store->mech = &dflt_mech;
    }

    /* Generate a key and parameters to do the encryption */
    store->key = PK11_TokenKeyGenWithFlags(store->slot, store->mech->type,
                 0, 0, 0, CKF_ENCRYPT|CKF_DECRYPT,
                 0, 0);
    if (store->key == 0)
    {
      /* PR_SetError(xxx); */
      err = SVRCORE_System_Error;
      break;
    }

    store->params = PK11_GenerateNewParam(store->mech->type, store->key);
    if (store->params == 0)
    {
      err = SVRCORE_System_Error;
      break;
    }

    /* Compute the size of the encrypted data including necessary padding */
    {
      int blocksize = PK11_GetBlockSize(store->mech->type, 0);

      store->length = strlen(pin)+1;

      /* Compute padded size - 0 means stream cipher */
      if (blocksize != 0)
      {
        store->length += blocksize - (store->length % blocksize);
      }

      store->crypt = (unsigned char *)malloc(store->length);
      if (!store->crypt) { err = SVRCORE_NoMemory_Error; break; }
    }

    /* Encrypt */
    {
      unsigned char *plain;
      PK11Context *ctx;
      SECStatus rv;
      int outLen;

      plain = (unsigned char *)malloc(store->length);
      if (!plain) { err = SVRCORE_NoMemory_Error; break; }

      /* Pad with 0 bytes */
      memset(plain, 0, store->length);
      strcpy((char *)plain, pin);

      ctx = PK11_CreateContextBySymKey(store->mech->type, CKA_ENCRYPT,
              store->key, store->params);
      if (!ctx) { err = SVRCORE_System_Error; break; }

      do {
        rv = PK11_CipherOp(ctx, store->crypt, &outLen, store->length,
               plain, store->length);
        if (rv) break;

        rv = PK11_Finalize(ctx);
      } while(0);

      PK11_DestroyContext(ctx, PR_TRUE);
      memset(plain, 0, store->length);
      free(plain);

      if (rv) err = SVRCORE_System_Error;
    }
  } while(0);

  if (err)
  {
    SVRCORE_DestroyPk11PinStore(store);
    store = 0;
  }

  *out = store;
  return err;
}
Esempio n. 13
0
int nsscrypto_init(
	knet_handle_t knet_h,
	struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
{
	struct nsscrypto_instance *nsscrypto_instance = NULL;

	log_debug(knet_h, KNET_SUB_NSSCRYPTO,
		  "Initizializing nss crypto module [%s/%s]",
		  knet_handle_crypto_cfg->crypto_cipher_type,
		  knet_handle_crypto_cfg->crypto_hash_type);

	knet_h->crypto_instance->model_instance = malloc(sizeof(struct nsscrypto_instance));
	if (!knet_h->crypto_instance->model_instance) {
		log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to allocate memory for nss model instance");
		return -1;
	}

	nsscrypto_instance = knet_h->crypto_instance->model_instance;

	memset(nsscrypto_instance, 0, sizeof(struct nsscrypto_instance));

	nsscrypto_instance->crypto_cipher_type = string_to_crypto_cipher_type(knet_handle_crypto_cfg->crypto_cipher_type);
	if (nsscrypto_instance->crypto_cipher_type < 0) {
		log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto cipher type requested");
		goto out_err;
	}

	nsscrypto_instance->crypto_hash_type = string_to_crypto_hash_type(knet_handle_crypto_cfg->crypto_hash_type);
	if (nsscrypto_instance->crypto_hash_type < 0) {
		log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto hash type requested");
		goto out_err;
	}

	if ((nsscrypto_instance->crypto_cipher_type > 0) &&
	    (nsscrypto_instance->crypto_hash_type == 0)) {
		log_err(knet_h, KNET_SUB_NSSCRYPTO, "crypto communication requires hash specified");
		goto out_err;
	}

	nsscrypto_instance->private_key = knet_handle_crypto_cfg->private_key;
	nsscrypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len;

	if (init_nss(knet_h) < 0) {
		goto out_err;
	}

	knet_h->sec_header_size = 0;

	if (nsscrypto_instance->crypto_hash_type > 0) {
		knet_h->sec_header_size += hash_len[nsscrypto_instance->crypto_hash_type];
		knet_h->sec_hash_size = hash_len[nsscrypto_instance->crypto_hash_type];
	}

	if (nsscrypto_instance->crypto_cipher_type > 0) {
		int block_size;

		if (cypher_block_len[nsscrypto_instance->crypto_cipher_type]) {
			block_size = cypher_block_len[nsscrypto_instance->crypto_cipher_type];
		} else {
			block_size = PK11_GetBlockSize(nsscrypto_instance->crypto_cipher_type, NULL);
			if (block_size < 0) {
				goto out_err;
			}
		}

		knet_h->sec_header_size += (block_size * 2);
		knet_h->sec_header_size += SALT_SIZE;
		knet_h->sec_salt_size = SALT_SIZE;
		knet_h->sec_block_size = block_size;
	}

	return 0;

out_err:
	nsscrypto_fini(knet_h);
	return -1;
}