Files
mars-matrixssl/crypto/pubkey/rsa_priv.c
Janne Johansson 5a72845b65 MatrixSSL 4.0.1
2018-11-15 10:12:51 +02:00

354 lines
10 KiB
C

/**
* @file rsa_priv.c
* @version $Format:%h%d$
*
* RSA private key operations.
*/
/*
* Copyright (c) 2013-2018 INSIDE Secure Corporation
* Copyright (c) PeerSec Networks, 2002-2011
* All Rights Reserved
*
* The latest version of this code is available at http://www.matrixssl.org
*
* This software is open source; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This General Public License does NOT permit incorporating this software
* into proprietary programs. If you are unable to comply with the GPL, a
* commercial license for this software may be purchased from INSIDE at
* http://www.insidesecure.com/
*
* This program is distributed in WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* http://www.gnu.org/copyleft/gpl.html
*/
/******************************************************************************/
#include "../cryptoImpl.h"
/******************************************************************************/
/* TODO - the following functions are not implementation layer specific...
move to a common file?
Matrix-specific starts at #ifdef USE_MATRIX_RSA
*/
#define ASN_OVERHEAD_LEN_RSA_SHA2 19
#define ASN_OVERHEAD_LEN_RSA_SHA1 15
#ifdef USE_MATRIX_RSA
/*
ASN wrappers around standard hash signatures. These versions sign
a BER wrapped hash. Here are the well-defined wrappers:
*/
static const unsigned char asn256dsWrap[] =
{
0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20
};
# ifdef USE_SHA384
static const unsigned char asn384dsWrap[] =
{
0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30
};
# endif
static const unsigned char asn1dsWrap[] =
{
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E,
0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14
};
int32_t privRsaEncryptSignedElement(psPool_t *pool, psRsaKey_t *key,
const unsigned char *in, psSize_t inlen,
unsigned char *out, psSize_t outlen,
void *data)
{
unsigned char c[MAX_HASH_SIZE + ASN_OVERHEAD_LEN_RSA_SHA2];
uint32_t inlenWithAsn;
switch (inlen)
{
# ifdef USE_SHA256
case SHA256_HASH_SIZE:
inlenWithAsn = inlen + ASN_OVERHEAD_LEN_RSA_SHA2;
Memcpy(c, asn256dsWrap, ASN_OVERHEAD_LEN_RSA_SHA2);
Memcpy(c + ASN_OVERHEAD_LEN_RSA_SHA2, in, inlen);
break;
# endif
# ifdef USE_SHA1
case SHA1_HASH_SIZE:
inlenWithAsn = inlen + ASN_OVERHEAD_LEN_RSA_SHA1;
Memcpy(c, asn1dsWrap, ASN_OVERHEAD_LEN_RSA_SHA1);
Memcpy(c + ASN_OVERHEAD_LEN_RSA_SHA1, in, inlen);
break;
# endif
# ifdef USE_SHA384
case SHA384_HASH_SIZE:
inlenWithAsn = inlen + ASN_OVERHEAD_LEN_RSA_SHA2;
Memcpy(c, asn384dsWrap, ASN_OVERHEAD_LEN_RSA_SHA2);
Memcpy(c + ASN_OVERHEAD_LEN_RSA_SHA2, in, inlen);
break;
# endif
default:
return PS_UNSUPPORTED_FAIL;
}
if (psRsaEncryptPriv(pool, key, c, inlenWithAsn,
out, outlen, data) < 0)
{
psTraceCrypto("privRsaEncryptSignedElement failed\n");
memzero_s(c, sizeof(c));
return PS_PLATFORM_FAIL;
}
memzero_s(c, sizeof(c));
return PS_SUCCESS;
}
/******************************************************************************/
/**
RSA private encryption. This is used by a private key holder to sign
data that can be verified by psRsaDecryptPub().
@param[in] pool Pool to use for temporary memory allocation for this op.
@param[in] key RSA key to use for this operation.
@param[in] in Pointer to allocated buffer to encrypt.
@param[in] inlen Number of bytes pointed to by 'in' to encrypt.
@param[out] out Pointer to allocated buffer to store encrypted data.
@param[out] outlen Number of bytes written to 'out' buffer.
@param[in] data TODO Hardware context.
@return 0 on success, < 0 on failure.
*/
int32_t psRsaEncryptPriv(psPool_t *pool, psRsaKey_t *key,
const unsigned char *in, psSize_t inlen,
unsigned char *out, psSize_t outlen,
void *data)
{
unsigned char *verify = NULL;
unsigned char *tmpout = NULL;
int32_t err;
psSize_t size, olen;
/** @security We follow the FIPS 186 recommendation for minimum data to sign. */
if (inlen < 28)
{
psTraceCrypto("Error inlen < 28 bytes in psRsaEncryptPriv\n");
return PS_ARG_FAIL;
}
size = key->size;
if (outlen < size)
{
psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPriv\n");
return PS_ARG_FAIL;
}
olen = outlen; /* Save in case we zero 'out' later */
if ((err = pkcs1Pad(in, inlen, out, size, PS_PUBKEY, data)) < PS_SUCCESS)
{
psTraceCrypto("Error padding psRsaEncryptPriv. Likely data too long\n");
return err;
}
if ((err = psRsaCrypt(pool, key, out, size, out, &outlen,
PS_PRIVKEY, data)) < PS_SUCCESS)
{
psTraceCrypto("Error performing psRsaEncryptPriv\n");
return err;
}
if (outlen != size)
{
goto L_FAIL;
}
/**
@security Verify the signature we just made before it is used
by the caller. If the signature is invalid for some reason
(hardware or software error or memory overrun), it can
leak information on the private key.
*/
if ((verify = psMalloc(pool, inlen)) == NULL)
{
goto L_FAIL;
}
/* psRsaDecryptPub overwrites the input, so duplicate it here */
if ((tmpout = psMalloc(pool, outlen)) == NULL)
{
goto L_FAIL;
}
Memcpy(tmpout, out, outlen);
if (psRsaDecryptPub(pool, key,
tmpout, outlen, verify, inlen, data) < 0)
{
goto L_FAIL;
}
if (memcmpct(in, verify, inlen) != 0)
{
goto L_FAIL;
}
memzero_s(verify, inlen);
psFree(verify, pool);
memzero_s(tmpout, outlen);
psFree(tmpout, pool);
return PS_SUCCESS;
L_FAIL:
memzero_s(out, olen); /* Clear, to ensure bad result isn't used */
if (tmpout)
{
memzero_s(tmpout, outlen);
psFree(tmpout, pool);
}
if (verify)
{
memzero_s(verify, inlen);
psFree(verify, pool);
}
psTraceCrypto("Signature mismatch in psRsaEncryptPriv\n");
return PS_FAIL;
}
/******************************************************************************/
/**
RSA private decryption. This is used by a private key holder to decrypt
a key exchange with the public key holder, which encodes the key using
psRsaEncryptPub().
@param[in] pool Pool to use for temporary memory allocation for this op.
@param[in] key RSA key to use for this operation.
@param[in,out] in Pointer to allocated buffer to encrypt.
@param[in] inlen Number of bytes pointed to by 'in' to encrypt.
@param[out] out Pointer to allocated buffer to store encrypted data.
@param[out] outlen Number of bytes written to 'out' buffer.
@param[in] data TODO Hardware context.
@return 0 on success, < 0 on failure.
TODO -fix
@note this function writes over the 'in' buffer
*/
int32_t psRsaDecryptPriv(psPool_t *pool, psRsaKey_t *key,
unsigned char *in, psSize_t inlen,
unsigned char *out, psSize_t outlen,
void *data)
{
int32_t err;
psSize_t ptLen;
if (inlen != key->size)
{
psTraceCrypto("Error on bad inlen parameter to psRsaDecryptPriv\n");
return PS_ARG_FAIL;
}
ptLen = inlen;
if ((err = psRsaCrypt(pool, key, in, inlen, in, &ptLen,
PS_PRIVKEY, data)) < PS_SUCCESS)
{
psTraceCrypto("Error performing psRsaDecryptPriv\n");
return err;
}
if (ptLen != inlen)
{
psTraceCrypto("Decrypted size error in psRsaDecryptPriv\n");
return PS_FAILURE;
}
err = pkcs1Unpad(in, inlen, out, outlen, PS_PRIVKEY);
Memset(in, 0x0, inlen);
return err;
}
# ifdef USE_PKCS1_PSS
/* Sign a hash using RSASSA-PSS (PKCS #2.1) */
int32_t psRsaPssSignHash(psPool_t *pool,
psPubKey_t *privKey,
int32_t sigAlg,
const unsigned char *in,
psSizeL_t inLen,
unsigned char **out,
psSize_t *outLen,
psSignOpts_t *opts)
{
unsigned char *em, *sig;
psSize_t emLen, sigLen;
psSize_t modNBytes = privKey->keysize;
psSize_t modNBits = modNBytes * 8;
int32_t rc;
psAssert(opts != NULL);
em = psMalloc(pool, modNBytes);
if (em == NULL)
{
return PS_MEM_FAIL;
}
emLen = modNBytes;
rc = psPkcs1PssEncode(pool,
in,
inLen,
opts->rsaPssSalt,
opts->rsaPssSaltLen,
opts->rsaPssHashAlg,
modNBits,
em,
&emLen);
if (rc < 0)
{
psFree(em, pool);
return rc;
}
sig = psMalloc(pool, modNBytes);
if (sig == NULL)
{
psFree(em, pool);
return PS_MEM_FAIL;
}
sigLen = modNBytes;
rc = psRsaCrypt(pool,
&privKey->key.rsa,
em,
emLen,
sig,
&sigLen,
PS_PRIVKEY,
NULL);
if (rc < 0)
{
psFree(em, pool);
psFree(sig, pool);
return rc;
}
psFree(em, pool);
*out = sig;
*outLen = sigLen;
# ifdef DEBUG_RSA_PSS
psTraceBytes("psRsaPssSignHash in", in, inLen);
psTraceBytes("psRsaPssSignHash sig", sig, sigLen);
psTraceIntCrypto("psRsaPssSignHash saltLen: %hu\n", opts->rsaPssSaltLen);
# endif
return PS_SUCCESS;
}
# endif
#endif /* USE_MATRIX_RSA */
/******************************************************************************/