/* Private key static functions. */ static void SecECPrivateKeyDestroy(SecKeyRef key) { /* Zero out the public key */ ccec_full_ctx_t fullkey; fullkey.hdr = key->key; if (ccec_ctx_cp(fullkey).zp) cc_zero(ccec_full_ctx_size(ccn_sizeof_n(ccec_ctx_n(fullkey))), fullkey.hdr); }
static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh) { void *p = dh; cczp_t zp = { .u = p }; cc_size s = ccn_sizeof_n(cczp_n(zp)); ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) }; return priv; } static inline size_t SecDH_context_size(size_t p_len) { cc_size n = ccn_nof_size(p_len); cc_size real_p_len = ccn_sizeof_n(n); size_t context_size = ccdh_gp_size(real_p_len)+ccdh_full_ctx_size(real_p_len); return context_size; }
/* Set DH parameters - Server only */ int tls_handshake_set_dh_parameters(tls_handshake_t filter, tls_buffer *params) { assert(filter->isServer); assert(params); const uint8_t *der, *der_end; size_t n; der = params->data; der_end = params->data + params->length; n = ccder_decode_dhparam_n(der, der_end); sslFree(filter->dhParams.gp); filter->dhParams.gp = sslMalloc(ccdh_gp_size(ccn_sizeof_n(n))); if(!filter->dhParams.gp) { return errSSLAllocate; } CCDH_GP_N(filter->dhParams) = n; der = ccder_decode_dhparams(filter->dhParams, der, der_end); if (der == NULL) { return errSSLParam; } else { return 0; } }
/* Public key static functions. */ static void SecECPublicKeyDestroy(SecKeyRef key) { /* Zero out the public key */ ccec_pub_ctx_t pubkey; pubkey.pub = key->key; if (ccec_ctx_cp(pubkey).zp) cc_zero(ccec_pub_ctx_size(ccn_sizeof_n(ccec_ctx_n(pubkey))), pubkey.pub); }
void SecDHDestroy(SecDHContext dh) { /* Zero out key material. */ ccdh_gp_t gp = SecDH_gp(dh); cc_size p_len = ccn_sizeof_n(ccdh_gp_n(gp)); size_t context_size = SecDH_context_size(p_len); bzero(dh, context_size); free(dh); }
OSStatus SecDHCreateFromParameters(const uint8_t *params, size_t params_len, SecDHContext *pdh) { DERReturn drtn; DERItem paramItem = {(DERByte *)params, params_len}; DER_DHParams decodedParams; uint32_t l; drtn = DERParseSequence(¶mItem, DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs, &decodedParams, sizeof(decodedParams)); if(drtn) return drtn; drtn = DERParseInteger(&decodedParams.l, &l); if(drtn) return drtn; cc_size n = ccn_nof_size(decodedParams.p.length); cc_size p_len = ccn_sizeof_n(n); size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len); void *context = malloc(context_size); if(context==NULL) return errSecAllocate; bzero(context, context_size); ccdh_gp_t gp; gp.gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data)) goto errOut; if(decodedParams.recip.length) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data)) goto errOut; gp.zp.zp->mod_prime = cczp_mod; } else { cczp_init(gp.zp); }; if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data)) goto errOut; *pdh = (SecDHContext) context; return errSecSuccess; errOut: SecDHDestroy(context); *pdh = NULL; return errSecInvalidKey; }
static OSStatus SecECPublicKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { ccec_pub_ctx_t pubkey; pubkey.pub = key->key; OSStatus err = errSecParam; switch (encoding) { case kSecDERKeyEncoding: { const SecDERKey *derKey = (const SecDERKey *)keyData; if (keyDataLength != sizeof(SecDERKey)) { err = errSecDecode; break; } ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength); /* TODO: Parse and use real params from passed in derKey->algId.params */ err = (ccec_import_pub(cp, derKey->keyLength, derKey->key, pubkey) ? errSecDecode : errSecSuccess); break; } case kSecKeyEncodingBytes: { ccec_const_cp_t cp = getCPForPublicSize(keyDataLength); err = (ccec_import_pub(cp, keyDataLength, keyData, pubkey) ? errSecDecode : errSecSuccess); break; } case kSecExtractPublicFromPrivate: { ccec_full_ctx_t fullKey; fullKey._full = (ccec_full_ctx *) keyData; cc_size fullKeyN = ccec_ctx_n(fullKey); require(fullKeyN <= ccn_nof(kMaximumECKeySize), errOut); memcpy(pubkey._pub, fullKey.pub, ccec_pub_ctx_size(ccn_sizeof_n(fullKeyN))); err = errSecSuccess; break; } case kSecKeyEncodingApplePkcs1: default: err = errSecParam; break; } errOut: return err; }
void ccz_lsl(ccz *r, const ccz *s, size_t k) { ccz_set_sign(r, ccz_sign(s)); ccz_set_capacity(r, ccz_n(s) + ccn_nof(k)); cc_size kn = k / CCN_UNIT_BITS; k &= (CCN_UNIT_BITS - 1); if (k) { r->u[kn + ccz_n(s)] = ccn_shift_left(ccz_n(s), r->u + kn, s->u, k); ccz_set_n(r, ccn_n(ccz_n(s) + kn + 1, r->u)); } else if (kn || r != s) { /* Must copy in reverse due to potential overlap. */ CC_MEMMOVE(r->u + kn, s->u, ccn_sizeof_n(ccz_n(s))); ccz_set_n(r, ccz_n(s) + kn); } ccn_zero(kn, r->u); }
int ccn_random_bits(cc_size nbits, cc_unit *r, struct ccrng_state *rng) { cc_size n = ccn_nof(nbits); int result = ccrng_generate(rng, ccn_sizeof_n(n), r); if (result) { return result; } cc_size lbits = nbits & (CCN_UNIT_BITS - 1); if (lbits) { cc_unit msuMask = (~CC_UNIT_C(0)) >> (CCN_UNIT_BITS - lbits); r[n - 1] &= msuMask; } return result; }
static OSStatus SecRSAPublicKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { OSStatus result = errSecParam; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; // Set maximum size for parsers ccrsa_ctx_n(pubkey) = ccn_nof(kMaximumRSAKeyBits); switch (encoding) { case kSecKeyEncodingBytes: // Octets is PKCS1 case kSecKeyEncodingPkcs1: result = ccrsa_pub_decode(pubkey, keyDataLength, keyData); break; case kSecKeyEncodingApplePkcs1: result = ccrsa_pub_decode_apple(pubkey, keyDataLength, keyData); break; case kSecKeyEncodingRSAPublicParams: { SecRSAPublicKeyParams *params = (SecRSAPublicKeyParams *)keyData; require_noerr(ccrsa_pub_init(pubkey, params->modulusLength, params->modulus, params->exponentLength, params->exponent), errOut); result = errSecSuccess; break; } case kSecExtractPublicFromPrivate: { ccrsa_full_ctx_t fullKey; fullKey.full = (ccrsa_full_ctx*) keyData; cc_size fullKeyN = ccrsa_ctx_n(fullKey); require(fullKeyN <= ccrsa_ctx_n(pubkey), errOut); memcpy(pubkey.pub, ccrsa_ctx_public(fullKey).pub, ccrsa_pub_ctx_size(ccn_sizeof_n(fullKeyN))); result = errSecSuccess; break; } default: break; } errOut: return result; }
static OSStatus SecRSAPublicKeyRawEncrypt(SecKeyRef key, SecPadding padding, const uint8_t *plainText, size_t plainTextLen, uint8_t *cipherText, size_t *cipherTextLen) { OSStatus result = errSecParam; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; const size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); require(cipherTextLen, errOut); require(*cipherTextLen >= m_size, errOut); uint8_t* sBytes = (uint8_t*) s; switch (padding) { case kSecPaddingNone: require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(pubkey), s, plainTextLen, plainText), errOut); require_quiet(ccn_cmp(ccrsa_ctx_n(pubkey), s, ccrsa_ctx_m(pubkey)) < 0, errOut); break; case kSecPaddingPKCS1: { // Create PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // const int kMinimumPadding = 1 + 1 + 8 + 1; require_quiet(plainTextLen < m_size - kMinimumPadding, errOut); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) *sBytes++ = 0x00; size_t pad_size = m_size - plainTextLen; *sBytes++ = 0x00; *sBytes++ = RSA_PKCS1_PAD_ENCRYPT; ccrng_generate(ccrng_seckey, pad_size - 3, sBytes); // Remove zeroes from the random pad const uint8_t* sEndOfPad = sBytes + (pad_size - 3); while (sBytes < sEndOfPad) { if (*sBytes == 0x00) *sBytes = 0xFF; // Michael said 0xFF was good enough. ++sBytes; } *sBytes++ = 0x00; memcpy(sBytes, plainText, plainTextLen); ccn_swap(ccrsa_ctx_n(pubkey), s); break; } case kSecPaddingOAEP: { const struct ccdigest_info* di = ccsha1_di(); const size_t encodingOverhead = 2 + 2 * di->output_size; require_action(m_size > encodingOverhead, errOut, result = errSecParam); require_action_quiet(plainTextLen < m_size - encodingOverhead, errOut, result = errSSLCrypto); require_noerr_action(ccrsa_oaep_encode(di, ccrng_seckey, m_size, s, plainTextLen, plainText), errOut, result = errSecInternal); break; } default: goto errOut; } ccrsa_pub_crypt(pubkey, s, s); ccn_write_uint_padded(ccrsa_ctx_n(pubkey), s, m_size, cipherText); *cipherTextLen = m_size; result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(pubkey), s); return result; }
static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh) { void *p = dh; cczp_t zp = { .u = p }; cc_size s = ccn_sizeof_n(cczp_n(zp)); ccdh_full_ctx_t priv = { .hdr = (struct ccdh_ctx_header *)(p+ccdh_gp_size(s)) }; return priv; } static uint32_t param_g = 5; static const uint8_t param_p[] = { 0xED, 0x42, 0x06, 0xE1, 0xDD, 0x09, 0x93, 0xA6, 0x81, 0xAE, 0x00, 0x0D, 0xBF, 0x84, 0x7F, 0x7D, 0x87, 0x64, 0x6B, 0x77, 0x24, 0x03, 0xB8, 0xC0, 0xDC, 0xBE, 0x5B, 0x9C, 0x8E, 0x71, 0x09, 0x24, 0x53, 0x77, 0x7F, 0x5D, 0x1A, 0xAD, 0x92, 0xD8, 0xFE, 0xCD, 0x5C, 0xB4, 0xCA, 0x09, 0x17, 0x11, 0xF3, 0x82, 0x01, 0x39, 0x4A, 0x09, 0xBA, 0x29, 0x95, 0x2B, 0xC4, 0xCC, 0x56, 0x21, 0x97, 0x13 }; static const uint8_t client_priv[] = { 0x32, 0x34, 0x73, 0x16, 0x7d, 0x79, 0xde, 0x47, 0x22, 0x93, 0xf5, 0x86, 0x47, 0xf6, 0x7f, 0x7a, 0xb6, 0x30, 0x16, 0x5b, 0xbf, 0xe1, 0x36, 0x0b, 0xb4, 0xd2, 0x84, 0x3e, 0x57, 0x5f, 0xcb, 0xc6, 0x6a, 0xae, 0x5d, 0x59, 0x4b, 0x70, 0x53, 0x22, 0xb0, 0x51, 0x89, 0x30, 0x74, 0xfc, 0x95, 0x51, 0x9c, 0xc9, 0xf7, 0xac, 0x8c, 0x37, 0xfd, 0xc1, 0x0e, 0x02, 0x6e, 0x69, 0x6c, 0xca, 0x2a, 0x95 }; static const uint8_t client_pub[] = { 0x15, 0xDF, 0x17, 0x6E, 0xB4, 0x95, 0xA7, 0x92, 0x41, 0xB6, 0xF1, 0x93, 0x19, 0xDB, 0x34, 0xF1, 0xE0, 0x0D, 0x62, 0xCD, 0x55, 0xC7, 0x0B, 0x27, 0xB7, 0x53, 0x1A, 0x28, 0x65, 0x11, 0xF0, 0xF6, 0xA6, 0xE1, 0x5B, 0x86, 0x1D, 0x67, 0x85, 0x19, 0x6D, 0xD6, 0x80, 0xFF, 0x5C, 0xEB, 0xC3, 0x2D, 0xC3, 0xCB, 0xD2, 0xD4, 0x66, 0x93, 0xF4, 0xFC, 0xF1, 0xF4, 0x8B, 0x61, 0x0F, 0x02, 0xF5, 0x19 }; static const uint8_t server_pub[] = { 0x73, 0xC5, 0xF8, 0xF8, 0xB8, 0x9C, 0xB0, 0x5F, 0xD6, 0xC6, 0x49, 0x5C, 0x70, 0xF5, 0x90, 0xB3, 0x8A, 0xD3, 0xD0, 0x12, 0x99, 0x47, 0x60, 0xC2, 0x5B, 0xF7, 0x18, 0x3A, 0x19, 0xF5, 0x01, 0xA3, 0x67, 0xBF, 0x57, 0x28, 0x7E, 0x99, 0xA8, 0xDB, 0x97, 0xA4, 0xAF, 0xF2, 0x68, 0x47, 0xAB, 0x48, 0xE3, 0x4D, 0xF2, 0x94, 0xB4, 0xCC, 0xFC, 0x0C, 0x50, 0xAD, 0xEF, 0x2E, 0x80, 0xA6, 0x20, 0x29 }; static const uint8_t pw[] = { 0x31, 0x32, 0x33, 0x34 }; static const uint8_t pw_encr[] = { 0x42, 0xd7, 0xa1, 0x08, 0x15, 0x8f, 0xdd, 0xc8, 0xe8, 0x75, 0xea, 0xa2, 0xc2, 0x20, 0x28, 0xfa }; #if 0 static void hexdump(const uint8_t *bytes, size_t len) { size_t ix; for (ix = 0; ix < len; ++ix) { printf("%02X", bytes[ix]); } printf("\n"); }
size_t SecDHGetMaxKeyLength(SecDHContext dh) { cczp_const_t zp; zp.u = (cc_unit *)dh; return ccn_sizeof_n(cczp_n(zp)); }
OSStatus SecDHCreateFromParameters(const uint8_t *params, size_t params_len, SecDHContext *pdh) { // We support DomainParameters as specified in PKCS#3 // (http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm) // DHParameter ::= SEQUENCE { // prime INTEGER, -- p // base INTEGER, -- g // privateValueLength INTEGER OPTIONAL } DERReturn drtn; DERItem paramItem = {(DERByte *)params, params_len}; DER_DHParams decodedParams; uint32_t l = 0; drtn = DERParseSequence(¶mItem, DER_NumDHParamsItemSpecs, DER_DHParamsItemSpecs, &decodedParams, sizeof(decodedParams)); if(drtn) return drtn; if (decodedParams.l.length > 0) { drtn = DERParseInteger(&decodedParams.l, &l); if(drtn) return drtn; } cc_size n = ccn_nof_size(decodedParams.p.length); cc_size p_len = ccn_sizeof_n(n); size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len); void *context = malloc(context_size); if(context==NULL) return errSecAllocate; bzero(context, context_size); ccdh_gp_t gp; gp.gp = context; CCDH_GP_N(gp) = n; CCDH_GP_L(gp) = l; if(ccn_read_uint(n, CCDH_GP_PRIME(gp), decodedParams.p.length, decodedParams.p.data)) goto errOut; if(decodedParams.recip.length) { if(ccn_read_uint(n+1, CCDH_GP_RECIP(gp), decodedParams.recip.length, decodedParams.recip.data)) goto errOut; CCZP_MOD_PRIME(gp.zp) = cczp_mod; } else { cczp_init(gp.zp); }; if(ccn_read_uint(n, CCDH_GP_G(gp), decodedParams.g.length, decodedParams.g.data)) goto errOut; *pdh = (SecDHContext) context; return errSecSuccess; errOut: SecDHDestroy(context); *pdh = NULL; return errSecInvalidKey; }
static OSStatus SecRSAPrivateKeyRawDecrypt(SecKeyRef key, SecPadding padding, const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { OSStatus result = errSSLCrypto; ccrsa_full_ctx_t fullkey; fullkey.full = key->key; size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); cc_unit s[ccrsa_ctx_n(fullkey)]; uint8_t recoveredData[ccn_sizeof_n(ccrsa_ctx_n(fullkey))]; ccn_read_uint(ccrsa_ctx_n(fullkey), s, cipherTextLen, cipherText); ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(fullkey)); require(plainTextLen, errOut); switch (padding) { case kSecPaddingNone: ccn_swap(ccrsa_ctx_n(fullkey), s); // Skip Zeros since our contract is to do so. while (sBytes < sEnd && *sBytes == 0x00) ++sBytes; break; case kSecPaddingPKCS1: { ccn_swap(ccrsa_ctx_n(fullkey), s); // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); while (*sBytes != 0x00) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 non-zeros require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: { size_t length = sizeof(recoveredData); require_noerr_quiet(ccrsa_oaep_decode(ccsha1_di(), ccn_write_uint_size(ccrsa_ctx_n(fullkey),ccrsa_ctx_m(fullkey)), s, &length, recoveredData), errOut); sBytes = recoveredData; sEnd = recoveredData + length; break; } default: goto errOut; } require((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut); *plainTextLen = sEnd - sBytes; memcpy(plainText, sBytes, *plainTextLen); result = errSecSuccess; errOut: bzero(recoveredData, sizeof(recoveredData)); ccn_zero(ccrsa_ctx_n(fullkey), s); return result; }
static OSStatus SecRSAPrivateKeyRawSign(SecKeyRef key, SecPadding padding, const uint8_t *dataToSign, size_t dataToSignLen, uint8_t *sig, size_t *sigLen) { OSStatus result = errSecParam; ccrsa_full_ctx_t fullkey; fullkey.full = key->key; size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(fullkey), ccrsa_ctx_m(fullkey)); cc_unit s[ccrsa_ctx_n(fullkey)]; uint8_t* sBytes = (uint8_t*) s; require(sigLen, errOut); require(*sigLen >= m_size, errOut); switch (padding) { case kSecPaddingNone: require_noerr_quiet(ccn_read_uint(ccrsa_ctx_n(fullkey), s, dataToSignLen, dataToSign), errOut); require_quiet(ccn_cmp(ccrsa_ctx_n(fullkey), s, ccrsa_ctx_m(fullkey)) < 0, errOut); break; case kSecPaddingPKCS1: { // Create PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData // const int kMinimumPadding = 1 + 1 + 8 + 1; require(dataToSignLen < m_size - kMinimumPadding, errOut); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(fullkey)) - m_size; while (prefix_zeros--) *sBytes++ = 0x00; size_t pad_size = m_size - dataToSignLen; *sBytes++ = 0x00; *sBytes++ = RSA_PKCS1_PAD_SIGN; size_t ff_size; for(ff_size = pad_size - 3; ff_size > 0; --ff_size) *sBytes++ = 0xFF; *sBytes++ = 0x00; // Get the user data into s looking like a ccn. memcpy(sBytes, dataToSign, dataToSignLen); ccn_swap(ccrsa_ctx_n(fullkey), s); break; } case kSecPaddingOAEP: result = errSecParam; default: goto errOut; } ccrsa_priv_crypt(ccrsa_ctx_private(fullkey), s, s); // Pad with leading zeros to fit in modulus size ccn_write_uint_padded(ccrsa_ctx_n(fullkey), s, m_size, sig); *sigLen = m_size; result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(fullkey), s); return result; }
/* Private key static functions. */ static void SecRSAPrivateKeyDestroy(SecKeyRef key) { /* Zero out the public key */ ccrsa_full_ctx_t fullkey; fullkey.full = key->key; cc_zero(ccrsa_full_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(fullkey))), fullkey.full); }
int ccdh_test_compute_vector(const struct ccdh_compute_vector *v) { int result,r1,r2; const cc_size n = ccn_nof(v->len); const size_t s = ccn_sizeof_n(n); unsigned char z[v->zLen]; size_t zLen; unsigned char tmp[v->zLen]; // for negative testing uint32_t status=0; uint32_t nb_test=0; ccdh_gp_decl(s, gp); ccdh_full_ctx_decl(s, a); ccdh_full_ctx_decl(s, b); cc_unit p[n]; cc_unit g[n]; cc_unit r[n]; cc_unit q[n]; // Bail to errOut when unexpected error happens. // Try all usecases otherwise if((result=ccn_read_uint(n, p, v->pLen, v->p))) goto errOut; if((result=ccn_read_uint(n, g, v->gLen, v->g))) goto errOut; if((result=ccn_read_uint(n, q, v->qLen, v->q))) goto errOut; ccdh_init_gp_with_order(gp, n, p, g, q); ccdh_ctx_init(gp, a); ccdh_ctx_init(gp, b); if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->xaLen, v->xa))) // private key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_y(a), v->yaLen, v->ya))) // public key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_x(b), v->xbLen, v->xb))) // private key goto errOut; if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->ybLen, v->yb))) // public key goto errOut; /* * Main test */ /* try one side */ zLen = v->zLen; r1=ccdh_compute_key(a, b, r); ccn_write_uint_padded(n, r, zLen, z); r1|=memcmp(z, v->z, zLen); /* try the other side */ zLen = v->zLen; r2=ccdh_compute_key(b, a, r); ccn_write_uint_padded(n, r, zLen, z); r2|=memcmp(z, v->z, zLen); if ((!(r1||r2) && v->valid)||((r1||r2) && !v->valid)) { status|=1<<nb_test; } nb_test++; // We are done if the test is not valid if (!v->valid) goto doneOut; /* * Corner case / negative testing * Only applicable for valid tests */ /* Output is 1 (use private key is (p-1)/2)*/ if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->pLen, v->p))) // private key goto errOut; ccn_sub1(n,ccdh_ctx_x(a),ccdh_ctx_x(a),1); ccn_shift_right(n,ccdh_ctx_x(a),ccdh_ctx_x(a),1); if ((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } if((result=ccn_read_uint(n, ccdh_ctx_x(a), v->xaLen, v->xa))) // restore private key goto errOut; nb_test++; /* negative testing (1 < y < p-1)*/ /* public y = 0 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = 1 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); tmp[zLen-1]=1; if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = p */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) goto errOut; if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* public y = p-1 */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) { goto errOut; } ccn_sub1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),1); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* * When the order is in defined in the group * check that the implementation check the order of the public value: * public y = g+1 (for rfc5114 groups, g+1 is not of order q) */ if (ccdh_gp_order_bitlen(gp)) { if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->gLen, v->g))) { goto errOut; } ccn_add1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),1); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; } /* positive testing at the boundaries of (1 < y < p-1)*/ // Don't set the order in gp because 2 and p-2 are not of order q ccdh_init_gp(gp, n, p, g, 0); /* public y = 2 */ zLen = v->zLen; cc_zero(sizeof(tmp),tmp); tmp[zLen-1]=2; if((result=ccn_read_uint(n, ccdh_ctx_y(b), zLen, tmp))) { goto errOut; } if((result=ccdh_compute_key(a, b, r))==0) { status|=1<<nb_test; } nb_test++; /* public y = p-2 */ if((result=ccn_read_uint(n, ccdh_ctx_y(b), v->pLen, v->p))) { goto errOut; } ccn_sub1(n,ccdh_ctx_y(b),ccdh_ctx_y(b),2); if((result=ccdh_compute_key(a, b, r))==0) { status|=1<<nb_test; } nb_test++; /* Negative testing: p is even */ if((result=ccn_read_uint(n, p, v->pLen, v->p))) goto errOut; ccn_set_bit(p,0,0); // Set LS bit to 0 ccdh_init_gp(gp, n, p, g, 0); ccdh_ctx_init(gp, a); ccdh_ctx_init(gp, b); if((result=ccdh_compute_key(a, b, r))!=0) { status|=1<<nb_test; } nb_test++; /* Test aftermath */ doneOut: if ((nb_test==0) || (status!=((1<<nb_test)-1))) { result=1; } else { result=0; // Test is successful, Yeah! } errOut: return result; }
static OSStatus SecRSAPublicKeyRawVerify(SecKeyRef key, SecPadding padding, const uint8_t *signedData, size_t signedDataLen, const uint8_t *sig, size_t sigLen) { OSStatus result = errSSLCrypto; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; ccn_read_uint(ccrsa_ctx_n(pubkey), s, sigLen, sig); ccrsa_pub_crypt(pubkey, s, s); ccn_swap(ccrsa_ctx_n(pubkey), s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); switch (padding) { case kSecPaddingNone: // Skip leading zeros as long as s is bigger than signedData. while (((ptrdiff_t)signedDataLen < (sEnd - sBytes)) && (*sBytes == 0)) ++sBytes; break; case kSecPaddingPKCS1: { // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_SIGN), 0xFF .. 0x00, signedData // size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_SIGN, errOut); while (*sBytes == 0xFF) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 0xFFs require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: result = errSecParam; goto errOut; default: result = errSecUnimplemented; goto errOut; } // Compare the rest. require_quiet((sEnd - sBytes) == (ptrdiff_t)signedDataLen, errOut); require_quiet(memcmp(sBytes, signedData, signedDataLen) == 0, errOut); result = errSecSuccess; errOut: cc_zero(ccrsa_ctx_n(pubkey), s); return result; }
/* Public key static functions. */ static void SecRSAPublicKeyDestroy(SecKeyRef key) { /* Zero out the public key */ ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_zero(ccrsa_pub_ctx_size(ccn_sizeof_n(ccrsa_ctx_n(pubkey))), pubkey.pub); }
static OSStatus SecRSAPublicKeyRawDecrypt(SecKeyRef key, SecPadding padding, const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, size_t *plainTextLen) { OSStatus result = errSSLCrypto; ccrsa_pub_ctx_t pubkey; pubkey.pub = key->key; cc_unit s[ccrsa_ctx_n(pubkey)]; require_action_quiet(cipherText != NULL, errOut, result = errSecParam); require_action_quiet(plainText != NULL, errOut, result = errSecParam); require_action_quiet(plainTextLen != NULL, errOut, result = errSecParam); ccn_read_uint(ccrsa_ctx_n(pubkey), s, cipherTextLen, cipherText); ccrsa_pub_crypt(pubkey, s, s); ccn_swap(ccrsa_ctx_n(pubkey), s); const uint8_t* sBytes = (uint8_t*) s; const uint8_t* sEnd = (uint8_t*) (s + ccrsa_ctx_n(pubkey)); switch (padding) { case kSecPaddingNone: // Skip leading zeros // We return the bytes for a number and // trim leading zeroes while (sBytes < sEnd && *sBytes == 0x00) ++sBytes; break; case kSecPaddingPKCS1: { // Verify and skip PKCS1 padding: // // 0x00, 0x01 (RSA_PKCS1_PAD_ENCRYPT), 0xFF .. 0x00, signedData // size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); size_t prefix_zeros = ccn_sizeof_n(ccrsa_ctx_n(pubkey)) - m_size; while (prefix_zeros--) require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == 0x00, errOut); require_quiet(*sBytes++ == RSA_PKCS1_PAD_ENCRYPT, errOut); while (*sBytes != 0x00) { require_quiet(++sBytes < sEnd, errOut); } // Required to have at least 8 0xFFs require_quiet((sBytes - (uint8_t*)s) - 2 >= 8, errOut); require_quiet(*sBytes == 0x00, errOut); require_quiet(++sBytes < sEnd, errOut); break; } case kSecPaddingOAEP: result = errSecParam; default: goto errOut; } // Return the rest. require_action((sEnd - sBytes) <= (ptrdiff_t)*plainTextLen, errOut, result = errSecParam); *plainTextLen = sEnd - sBytes; memcpy(plainText, sBytes, *plainTextLen); result = errSecSuccess; errOut: ccn_zero(ccrsa_ctx_n(pubkey), s); return result; }
static int RSA_POST() { int result = -1; uint32_t uintEValue = 3; // xp1 = 1384167f9844865eae22cb3672 unsigned char* xp1Data = (unsigned char*)"\x13\x84\x16\x7f\x98\x44\x86\x5e\xae\x22\xcb\x36\x72"; size_t xp1DataSize = 13; // xp2 = 1a085b0b737f842a8a1f32b662 unsigned char* xp2Data = (unsigned char*)"\x1a\x08\x5b\x0b\x73\x7f\x84\x2a\x8a\x1f\x32\xb6\x62"; size_t xp2DataSize = 13; // Xp = beef5ad133e9a3955097c8d8b03bd50662b5f82b8e9c3eab5c8d9d3311c337ef7ce8ddfe902bd2235293d2bdf69353f944de0b46417cb2090c1e099206af1b4 unsigned char* xpData = (unsigned char*)"\xbe\xef\x5a\xd1\x33\xe9\xa3\x95\x50\x97\xc8\xd8\xb0\x3b\xd5\x06\x62\xb5\xf8\x2b\x8e\x9c\x3e\xab\x5c\x8d\x9d\x33\x11\xc3\x37\xef\x7c\xe8\xdd\xfe\x90\x2b\xd2\x23\x52\x93\xd2\xbd\xf6\x93\x53\xf9\x44\xde\x0b\x46\x41\x7c\xb2\x09\x0c\x1e\x09\x92\x06\xaf\x1b\x04"; size_t xpDataSize = 64; // xq1 = 17fa0d7d2189c759b0b8eb1d18 unsigned char* xq1Data = (unsigned char*)"\x17\xfa\x0d\x7d\x21\x89\xc7\x59\xb0\xb8\xeb\x1d\x18"; size_t xq1DataSize = 13; // xq2 = 17c8e735fb8d58e13a412ae214 unsigned char* xq2Data = (unsigned char*)"\x17\xc8\xe7\x35\xfb\x8d\x58\xe1\x3a\x41\x2a\xe2\x14"; size_t xq2DataSize = 13; // Xq = f2d7b992fb914cd677876bb3702b1441716ebd2b447c3a0500a6e0e0449feb1cbdec1d7eee96a88230224ef3f7c2c7b858cd63f1c86df0432798de6ffd41a12a unsigned char* xqData = (unsigned char*)"\xf2\xd7\xb9\x92\xfb\x91\x4c\xd6\x77\x87\x6b\xb3\x70\x2b\x14\x41\x71\x6e\xbd\x2b\x44\x7c\x3a\x05\x00\xa6\xe0\xe0\x44\x9f\xeb\x1c\xbd\xec\x1d\x7e\xee\x96\xa8\x82\x30\x22\x4e\xf3\xf7\xc2\xc7\xb8\x58\xcd\x63\xf1\xc8\x6d\xf0\x43\x27\x98\xde\x6f\xfd\x41\xa1\x2a"; size_t xqDataSize = 64; cc_unit x_p1[ccn_nof_size(xp1DataSize)]; cc_unit x_p2[ccn_nof_size(xp2DataSize)]; cc_unit x_p[ccn_nof_size(xpDataSize)]; cc_unit x_q1[ccn_nof_size(xq1DataSize)]; cc_unit x_q2[ccn_nof_size(xq2DataSize)]; cc_unit x_q[ccn_nof_size(xqDataSize)]; cc_unit e_value[1]; size_t nbits = xpDataSize * 8 + xqDataSize * 8; // or we'll add this as a parameter. This appears to be correct for FIPS cc_size n = ccn_nof(nbits); e_value[0] = (cc_unit)uintEValue; if (0 != ccn_read_uint(ccn_nof_size(xp1DataSize), x_p1, xp1DataSize, xp1Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xp2DataSize), x_p2, xp2DataSize, xp2Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xpDataSize), x_p, xpDataSize, xpData)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xq1DataSize), x_q1, xq1DataSize, xq1Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xq2DataSize), x_q2, xq2DataSize, xq2Data)) { return result; } if (0 != ccn_read_uint(ccn_nof_size(xqDataSize), x_q, xqDataSize, xqData)) { return result; }; cc_size np = n; cc_size nq = n; cc_size nm = n; cc_size nd = n; cc_unit p[n]; cc_unit q[n]; cc_unit m[n]; cc_unit d[n]; ccrsa_full_ctx_decl(ccn_sizeof_n(n), full_key); ccrsa_ctx_n(full_key) = n; if (0 != ccrsa_make_931_key(nbits, 1, e_value, ccn_nof_size(xp1DataSize), x_p1, ccn_nof_size(xp2DataSize), x_p2, ccn_nof_size(xpDataSize), x_p, ccn_nof_size(xq1DataSize), x_q1, ccn_nof_size(xq2DataSize), x_q2, ccn_nof_size(xqDataSize), x_q, full_key, &np, p, &nq, q, &nm, m, &nd, d)) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } ccrsa_full_ctx *fk = full_key; ccrsa_pub_ctx_t pub_key = ccrsa_ctx_public(fk); unsigned char fake_digest[20]; memcpy(fake_digest, "ABCEDFGHIJKLMNOPRSTU", 20); uint8_t sig[(nbits+7)/8]; size_t siglen=sizeof(sig); if (0 != ccrsa_sign_pkcs1v15(full_key, ccoid_sha1, CCSHA1_OUTPUT_SIZE, fake_digest, &siglen, sig)) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } bool ok; if (0 != ccrsa_verify_pkcs1v15(pub_key, ccoid_sha1, CCSHA1_OUTPUT_SIZE, fake_digest, siglen, sig, &ok) || !ok) { ccrsa_full_ctx_clear(ccn_sizeof(nbits), full_key); return result; } return 0; }