X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/cspxutils/dsaPartial/dsaPartial.cpp diff --git a/SecurityTests/cspxutils/dsaPartial/dsaPartial.cpp b/SecurityTests/cspxutils/dsaPartial/dsaPartial.cpp new file mode 100644 index 00000000..1434162d --- /dev/null +++ b/SecurityTests/cspxutils/dsaPartial/dsaPartial.cpp @@ -0,0 +1,724 @@ +/* + * dsaPartial.cpp - test for partial DSA public handling + */ +#include +#include +#include +#include +#include +#include +#include "cspwrap.h" +#include "common.h" +#include +#include "nssAppUtils.h" + +/* + * generate key pairs with one set of parameters, dsa1Priv and dsa1Pub; + * genenate another pair with a different set of params, dsa2Priv and + * dsa2Pub; + * manually cook up dsa1PubPartial from dsa1Pub; + * manually cook up dsa2PubPartial from dsa2Pub; + * + * with all legal and/or specified combos of {ref,raw} keys { + * sign with dsa1Priv; + * vfy with dsa1Pub; + * vfy with dsa1PubPartial: CSSMERR_CSP_APPLE_DSA_PUBLIC_KEY_INCOMPLETE + * vfy with dsa1PubPartial and dsa1Pub (attrs) + * vfy with dsa2PubPartial and dsa1Pub (attrs) --> vfy fail + * vfy with dsa1PubPartial and dsa2Pub (attrs) --> vfy fail + * merge dsa1PubPartial + dsa1Pub --> merged; + * vfy with merged, should be good + * merge dsa1PubPartial + dsa2Pub -->merged; + * vfy with merged; vfy fail; + * } + */ + +/* + * Static parameter files. + * + * Regenerate these every once in a while with rsatool: + * + * # rsatool g a=d k=/tmp/foo M=dsaParam512_1.der + */ +#define PARAMS_512_1 "dsaParam512_1.der" +#define PARAMS_512_2 "dsaParam512_2.der" + +#define MAX_PTEXT_SIZE 512 +#define KEY_ALG CSSM_ALGID_DSA +#define SIG_ALG CSSM_ALGID_SHA1WithDSA +#define LOOPS_DEF 32 +#define KEY_SIZE_DEF 512 + +static void usage(char **argv) +{ + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" l=loops\n"); + printf(" p(ause on loop)\n"); + printf(" q(uiet)\n"); + printf(" v(erbose)\n"); + printf(" D (CSPDL)\n"); + printf(" r (all keys are raw)\n"); + printf(" f (all keys are ref)\n"); + exit(1); +} + +/* + * Generate DSA key pair with required alg parameters. + */ +static CSSM_RETURN genDsaKeyPair( + CSSM_CSP_HANDLE cspHand, + uint32 keySize, // in bits + CSSM_KEY_PTR pubKey, // mallocd by caller + CSSM_BOOL pubIsRef, // true - reference key, false - data + CSSM_KEY_PTR privKey, // mallocd by caller + CSSM_BOOL privIsRef, // true - reference key, false - data + const CSSM_DATA *params) +{ + CSSM_RETURN crtn; + CSSM_CC_HANDLE ccHand; + CSSM_DATA keyLabelData; + uint32 pubAttr; + uint32 privAttr; + + if(params == NULL) { + return CSSMERR_CSSM_INVALID_POINTER; + } + + keyLabelData.Data = (uint8 *)"foobar", + keyLabelData.Length = 6; + memset(pubKey, 0, sizeof(CSSM_KEY)); + memset(privKey, 0, sizeof(CSSM_KEY)); + + crtn = CSSM_CSP_CreateKeyGenContext(cspHand, + CSSM_ALGID_DSA, + keySize, + NULL, // Seed + NULL, // Salt + NULL, // StartDate + NULL, // EndDate + params, + &ccHand); + if(crtn) { + printError("CSSM_CSP_CreateKeyGenContext", crtn); + return crtn; + } + + /* cook up attribute bits */ + if(pubIsRef) { + pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE; + } + else { + pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; + } + if(privIsRef) { + privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE; + } + else { + privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE; + } + + crtn = CSSM_GenerateKeyPair(ccHand, + CSSM_KEYUSE_VERIFY, + pubAttr, + &keyLabelData, + pubKey, + CSSM_KEYUSE_SIGN, + privAttr, + &keyLabelData, // same labels + NULL, // CredAndAclEntry + privKey); + if(crtn) { + printError("CSSM_GenerateKeyPair", crtn); + } + CSSM_DeleteContext(ccHand); + return crtn; +} + + +/* + * Create new public key by merging specified partial key and + * parameter-bearing key. All keys can be in any format (though + * it's the caller's responsibility to avoid using a ref paramKey + * with the CSPDL). + */ +static CSSM_RETURN dsaMergeParams( + CSSM_CSP_HANDLE cspHand, + const CSSM_KEY *partialKey, + const CSSM_KEY *paramKey, + CSSM_KEY &fullKey, // RETURNED + bool fullIsRef) // ref/raw +{ + /* + * First step is a null wrap or unwrap depending on + * format of partialKey. + */ + CSSM_CC_HANDLE ccHand; + CSSM_RETURN crtn; + CSSM_ACCESS_CREDENTIALS creds; + CSSM_DATA label = {10, (uint8 *)"dummyLabel"}; + CSSM_DATA descrData = {0, NULL}; + const CSSM_KEYHEADER &hdr = partialKey->KeyHeader; + + memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); + crtn = CSSM_CSP_CreateSymmetricContext(cspHand, + CSSM_ALGID_NONE, + CSSM_ALGMODE_NONE, + &creds, + NULL, // wrapping key + NULL, // initVector + CSSM_PADDING_NONE, + 0, // Params + &ccHand); + if(crtn) { + printError("CSSM_CSP_CreateSymmetricContext", crtn); + return crtn; + } + + /* add in paramKey */ + crtn = AddContextAttribute(ccHand, + CSSM_ATTRIBUTE_PARAM_KEY, + sizeof(CSSM_KEY), + CAT_Ptr, + paramKey, + 0); + if(crtn) { + printError("AddContextAttribute", crtn); + return crtn; + } + + /* go */ + CSSM_KEY targetKey; + memset(&targetKey, 0, sizeof(targetKey)); + if(hdr.BlobType == CSSM_KEYBLOB_RAW) { + /* raw --> ref : null unwrap */ + crtn = CSSM_UnwrapKey(ccHand, + NULL, // PublicKey + partialKey, + hdr.KeyUsage, // same as original + CSSM_KEYATTR_EXTRACTABLE |CSSM_KEYATTR_RETURN_REF, + &label, + NULL, // CredAndAclEntry + &targetKey, + &descrData); // required + if(crtn) { + printError("dsaMergeParams CSSM_UnwrapKey (1)", crtn); + return crtn; + } + } + else { + /* ref --> raw : null wrap */ + crtn = CSSM_WrapKey(ccHand, + &creds, + partialKey, + NULL, // DescriptiveData + &targetKey); + if(crtn) { + printError("dsaMergeParams CSSM_WrapKey (1)", crtn); + return crtn; + } + } + + if(targetKey.KeyHeader.KeyAttr & CSSM_KEYATTR_PARTIAL) { + printf("***merged key still has CSSM_KEYATTR_PARTIAL\n"); + return CSSMERR_CSSM_INTERNAL_ERROR; + } + + CSSM_KEYBLOB_TYPE targetBlob; + if(fullIsRef) { + targetBlob = CSSM_KEYBLOB_REFERENCE; + } + else { + targetBlob = CSSM_KEYBLOB_RAW; + } + + if(targetKey.KeyHeader.BlobType == targetBlob) { + /* we're done */ + fullKey = targetKey; + CSSM_DeleteContext(ccHand); + return CSSM_OK; + } + + /* + * We're going to reuse the context, but since the parameter merge + * has already been done, remove the CSSM_ATTRIBUTE_PARAM_KEY + * attribute. + */ + CSSM_CONTEXT_ATTRIBUTE attr; + memset(&attr, 0, sizeof(attr)); + attr.AttributeType = CSSM_ATTRIBUTE_PARAM_KEY; + crtn = CSSM_DeleteContextAttributes(ccHand, 1, &attr); + if(crtn) { + printError("CSSM_DeleteContextAttributes", crtn); + return crtn; + } + + /* one more conversion */ + if(targetBlob == CSSM_KEYBLOB_REFERENCE) { + /* raw --> ref : null unwrap */ + crtn = CSSM_UnwrapKey(ccHand, + NULL, // PublicKey + &targetKey, + hdr.KeyUsage, // same as original + CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF, + &label, + NULL, // CredAndAclEntry + &fullKey, + &descrData); // required + if(crtn) { + printError("dsaMergeParams CSSM_UnwrapKey (2)", crtn); + return crtn; + } + } + else { + /* ref --> raw : null wrap */ + crtn = CSSM_WrapKey(ccHand, + &creds, + &targetKey, + NULL, // DescriptiveData + &fullKey); + if(crtn) { + printError("dsaMergeParams CSSM_WrapKey (2)", crtn); + return crtn; + } + } + CSSM_FreeKey(cspHand, NULL, &targetKey, CSSM_FALSE); + CSSM_DeleteContext(ccHand); + return CSSM_OK; +} + +/* + * Custom cspSigVerify with optional CSSM_ATTRIBUTE_PARAM_KEY + */ +CSSM_RETURN sigVerify(CSSM_CSP_HANDLE cspHand, + uint32 algorithm, // CSSM_ALGID_SHA1WithDSA, etc. + CSSM_KEY_PTR key, // public key + CSSM_KEY_PTR paramKey, // optional parameter key + const CSSM_DATA *ptext, + const CSSM_DATA *sig, + CSSM_RETURN expectResult, + const char *op, + CSSM_BOOL verbose) +{ + CSSM_CC_HANDLE sigHand; + CSSM_RETURN ocrtn = CSSM_OK; + CSSM_RETURN crtn; + + if(verbose) { + printf(" ...%s\n", op); + } + crtn = CSSM_CSP_CreateSignatureContext(cspHand, + algorithm, + NULL, // passPhrase + key, + &sigHand); + if(crtn) { + printError("CSSM_CSP_CreateSignatureContext", crtn); + return crtn; + } + if(paramKey) { + crtn = AddContextAttribute(sigHand, + CSSM_ATTRIBUTE_PARAM_KEY, + sizeof(CSSM_KEY), + CAT_Ptr, + paramKey, + 0); + if(crtn) { + printError("AddContextAttribute", crtn); + return crtn; + } + } + crtn = CSSM_VerifyData(sigHand, + ptext, + 1, + CSSM_ALGID_NONE, + sig); + if(crtn != expectResult) { + if(!crtn) { + printf("%s: Unexpected good Sig Verify (expect %s)\n", + op, cssmErrToStr(expectResult)); + ocrtn = CSSMERR_CSSM_INTERNAL_ERROR; + } + else { + printError(op, crtn); + ocrtn = crtn; + } + } + CSSM_DeleteContext(sigHand); + return ocrtn; +} + +static int doTest( + CSSM_CSP_HANDLE cspHand, + CSSM_KEY_PTR privKey_0, + CSSM_KEY_PTR pubKeyBase_0, + CSSM_KEY_PTR pubKeyPartial_0, + CSSM_KEY_PTR pubKeyParam_0, // full, raw format if CSPDL + CSSM_KEY_PTR pubKeyPartial_1, + CSSM_KEY_PTR pubKeyParam_1, // full, raw format if CSPDL + bool mergedIsRef, + CSSM_BOOL quiet, + CSSM_BOOL verbose) +{ + uint8 ptextBuf[MAX_PTEXT_SIZE]; + CSSM_DATA ptext = {0, ptextBuf}; + simpleGenData(&ptext, 1, MAX_PTEXT_SIZE); + CSSM_DATA sig = {0, NULL}; + CSSM_RETURN crtn; + + /* the single sign op for this routine */ + crtn = cspSign(cspHand, SIG_ALG, privKey_0, &ptext, &sig); + if(crtn) { + return testError(quiet); + } + + /* normal verify with full key */ + crtn = sigVerify(cspHand, SIG_ALG, pubKeyBase_0, NULL, + &ptext, &sig, CSSM_OK, "vfy with full key", verbose); + if(crtn) { + return testError(quiet); + } + + /* good verify with partial key plus params */ + crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, pubKeyParam_0, + &ptext, &sig, CSSM_OK, "vfy with partial key and params", + verbose); + if(crtn) { + if(testError(quiet)) { + return 1; + } + } + + /* partial key failure */ + crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, NULL, + &ptext, &sig, + CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE, + "vfy with partial key no params", verbose); + if(crtn) { + if(testError(quiet)) { + return 1; + } + } + + /* partial key, wrong params */ + crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_0, pubKeyParam_1, + &ptext, &sig, + CSSMERR_CSP_VERIFY_FAILED, + "vfy with partial key wrong params", verbose); + if(crtn) { + if(testError(quiet)) { + return 1; + } + } + + /* wrong partial key, good params */ + crtn = sigVerify(cspHand, SIG_ALG, pubKeyPartial_1, pubKeyParam_0, + &ptext, &sig, + CSSMERR_CSP_VERIFY_FAILED, + "vfy with wrong partial key, good params", verbose); + if(crtn) { + if(testError(quiet)) { + return 1; + } + } + + /* + * Test merge via wrap/unwrap. + * First, a good merged key. + */ + CSSM_KEY merged; + crtn = dsaMergeParams(cspHand, + pubKeyPartial_0, + pubKeyParam_0, + merged, + mergedIsRef); + if(crtn) { + return testError(quiet); + } + crtn = sigVerify(cspHand, SIG_ALG, &merged, NULL, + &ptext, &sig, CSSM_OK, "vfy with good merged key", verbose); + if(crtn) { + return testError(quiet); + } + CSSM_FreeKey(cspHand, NULL, &merged, CSSM_FALSE); + + /* now with a badly merged key (with the wrong params) */ + crtn = dsaMergeParams(cspHand, + pubKeyPartial_0, + pubKeyParam_1, + merged, + mergedIsRef); + if(crtn) { + return testError(quiet); + } + crtn = sigVerify(cspHand, SIG_ALG, &merged, NULL, + &ptext, &sig, + CSSMERR_CSP_VERIFY_FAILED, + "vfy with merged key wrong params", verbose); + if(crtn) { + if(testError(quiet)) { + return 1; + } + } + CSSM_FreeKey(cspHand, NULL, &merged, CSSM_FALSE); + + CSSM_FREE(sig.Data); + return CSSM_OK; +} + + +int main(int argc, char **argv) +{ + char *argp; + CSSM_CSP_HANDLE cspHand; + CSSM_RETURN crtn; + + /* user spec'd variables */ + unsigned loops = LOOPS_DEF; + CSSM_BOOL doPause = CSSM_FALSE; + CSSM_BOOL quiet = CSSM_FALSE; + CSSM_BOOL rawCSP = CSSM_TRUE; + CSSM_BOOL verbose = CSSM_FALSE; + uint32 keySize = KEY_SIZE_DEF; + CSSM_BOOL allRaw = CSSM_FALSE; + CSSM_BOOL allRef = CSSM_FALSE; + + for(int arg=1; arg these were created as ref keys + !allRaw && // allRaw --> don't want ref keys + !allRef) { // allRef --> these were created as ref keys + if(cspRawKeyToRef(cspHand, &dsa1Pub, &dsa1PubRef) || + cspRawKeyToRef(cspHand, &dsa2Pub, &dsa2PubRef)) { + exit(1); + } + } + if(!rawCSP || !allRaw) { + /* these were created in raw form unconditionally */ + if(cspRawKeyToRef(cspHand, &dsa1PubPartial, + &dsa1PubPartialRef) || + cspRawKeyToRef(cspHand, &dsa2PubPartial, + &dsa2PubPartialRef)) { + exit(1); + } + + /* verify that these came back with the partial flag set */ + if(!(dsa1PubPartialRef.KeyHeader.KeyAttr & + CSSM_KEYATTR_PARTIAL)) { + printf("***CSSM_KEYATTR_PARTIAL not set after null unwrap" + " of partial DSA key\n"); + if(testError(quiet)) { + exit(1); + } + } + if(!(dsa2PubPartialRef.KeyHeader.KeyAttr & + CSSM_KEYATTR_PARTIAL)) { + printf("***CSSM_KEYATTR_PARTIAL not set after null unwrap" + " of partial DSA key\n"); + if(testError(quiet)) { + exit(1); + } + } + } + + int rtn = 0; + for(unsigned loop=0; loop