int gen_hash( unsigned char *inbufp, int bsize, unsigned char *outbufp, CRYPT_ALGO_TYPE alg) { CRYPT_CONTEXT hashContext; unsigned char hash[40]; int ansr = -1; if (alg != CRYPT_ALGO_SHA1 && alg != CRYPT_ALGO_SHA2) return -1; memset(hash, 0, 40); if (cryptInit_wrapper() != CRYPT_OK) return -1; if (cryptCreateContext(&hashContext, CRYPT_UNUSED, alg) != CRYPT_OK) return -1; cryptEncrypt(hashContext, inbufp, bsize); cryptEncrypt(hashContext, inbufp, 0); if (cryptGetAttributeString( hashContext, CRYPT_CTXINFO_HASHVALUE, hash, &ansr) != CRYPT_OK) { return -1; } cryptDestroyContext(hashContext); if (ansr > 0) memcpy(outbufp, hash, ansr); return ansr; }
int main( int argc, char **argv) { CRYPT_CONTEXT privKeyContext; CRYPT_KEYSET cryptKeyset; if (argc < 2) { fprintf(stderr, "Usage: Filename\n"); return 1; } printf("Making %s\n", argv[1]); #define CRYPT_CALL(f) \ do \ { \ if ((f) != CRYPT_OK) \ { \ fprintf(stderr, "Error calling %s\n", #f); \ exit(EXIT_FAILURE); \ } \ } while (false) CRYPT_CALL(cryptInit_wrapper()); CRYPT_CALL(cryptCreateContext(&privKeyContext, CRYPT_UNUSED, CRYPT_ALGO_RSA)); CRYPT_CALL(cryptSetAttributeString(privKeyContext, CRYPT_CTXINFO_LABEL, "label", 5)); CRYPT_CALL(cryptSetAttribute(privKeyContext, CRYPT_CTXINFO_KEYSIZE, 1024 / 8)); CRYPT_CALL(cryptGenerateKey(privKeyContext)); CRYPT_CALL(cryptKeysetOpen(&cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, argv[1], CRYPT_KEYOPT_CREATE)); CRYPT_CALL(cryptAddPrivateKey(cryptKeyset, privKeyContext, "password")); CRYPT_CALL(cryptKeysetClose(cryptKeyset)); CRYPT_CALL(cryptDestroyContext(privKeyContext)); #undef CRYPT_CALL return 0; }
const char *signCMS( struct CMS *cms, const char *keyfilename, bool bad) { bool hashContext_initialized = false; CRYPT_CONTEXT hashContext; bool sigKeyContext_initialized = false; CRYPT_CONTEXT sigKeyContext; CRYPT_KEYSET cryptKeyset; int signatureLength; int tbs_lth; char *msg = (char *)0; uchar *tbsp; uchar *signature = NULL; uchar hash[40]; struct casn *sidp; struct Attribute *attrp; struct AttrTableDefined *attrtdp; struct SignerInfo *sigInfop; // signer info // firat clear out any old stuff in signerInfos that may have been put // there by old code while (num_items(&cms->content.signedData.signerInfos.self) > 0) eject_casn(&cms->content.signedData.signerInfos.self, 0); sigInfop = (struct SignerInfo *) inject_casn(&(cms->content.signedData.signerInfos.self), 0); // write the signature version (3) to the signer info write_casn_num(&sigInfop->version.self, 3); // find the SID if ((sidp = findSID(cms)) == NULL) return "finding SID"; // copy the CMS's SID over to the signature's SID copy_casn(&sigInfop->sid.subjectKeyIdentifier, sidp); // use sha256 as the algorithm write_objid(&sigInfop->digestAlgorithm.algorithm, id_sha256); // no parameters to sha256 write_casn(&sigInfop->digestAlgorithm.parameters.sha256, (uchar *) "", 0); // first attribute: content type attrp = (struct Attribute *)inject_casn(&sigInfop->signedAttrs.self, 0); write_objid(&attrp->attrType, id_contentTypeAttr); attrtdp = (struct AttrTableDefined *)inject_casn(&attrp->attrValues.self, 0); copy_casn(&attrtdp->contentType, &cms->content.signedData.encapContentInfo.eContentType); // second attribute: message digest attrp = (struct Attribute *)inject_casn(&sigInfop->signedAttrs.self, 1); write_objid(&attrp->attrType, id_messageDigestAttr); // create the hash for the content // first pull out the content if ((tbs_lth = readvsize_casn(&cms->content.signedData.encapContentInfo.eContent. self, &tbsp)) < 0) return "getting content"; // set up the context, initialize crypt memset(hash, 0, 40); if (cryptInit_wrapper() != CRYPT_OK) return "initializing cryptlib"; // the following calls function f, and if f doesn't return 0 sets // msg to m, then breaks out of the loop. Used immediately below. #define CALL(f,m) if (f != 0) { msg = m; break; } // use a "do { ... } while (0)" loop to bracket this code, so we can // bail out on failure. (Note that this construct isn't really a // loop; it's a way to use break as a more clean version of goto.) do { // first sign the body of the message // create the context CALL(cryptCreateContext(&hashContext, CRYPT_UNUSED, CRYPT_ALGO_SHA2), "creating context"); hashContext_initialized = true; // generate the hash CALL(cryptEncrypt(hashContext, tbsp, tbs_lth), "hashing"); CALL(cryptEncrypt(hashContext, tbsp, 0), "hashing"); // get the hash value. then we're done, so destroy it CALL(cryptGetAttributeString (hashContext, CRYPT_CTXINFO_HASHVALUE, hash, &signatureLength), "getting first hash"); CALL(cryptDestroyContext(hashContext), "destroying intermediate context"); // insert the hash as the first attribute attrtdp = (struct AttrTableDefined *)inject_casn(&attrp->attrValues.self, 0); write_casn(&attrtdp->messageDigest, hash, signatureLength); // create signing time attribute; mark the signing time as now if (getenv("RPKI_NO_SIGNING_TIME") == NULL) { attrp = (struct Attribute *)inject_casn(&sigInfop->signedAttrs.self, 2); write_objid(&attrp->attrType, id_signingTimeAttr); attrtdp = (struct AttrTableDefined *)inject_casn(&attrp->attrValues.self, 0); write_casn_time(&attrtdp->signingTime.utcTime, time((time_t *) 0)); } // we are all done with the content free(tbsp); // now sign the attributes // get the size of signed attributes and allocate space for them if ((tbs_lth = size_casn(&sigInfop->signedAttrs.self)) < 0) { msg = "sizing SignerInfo"; break; } tbsp = (uchar *) calloc(1, tbs_lth); encode_casn(&sigInfop->signedAttrs.self, tbsp); *tbsp = ASN_SET; // create a new, fresh hash context for hashing the attrs, and hash // them CALL(cryptCreateContext(&hashContext, CRYPT_UNUSED, CRYPT_ALGO_SHA2), "creating hash context"); CALL(cryptEncrypt(hashContext, tbsp, tbs_lth), "hashing attrs"); CALL(cryptEncrypt(hashContext, tbsp, 0), "hashing attrs"); // get the hash value CALL(cryptGetAttributeString (hashContext, CRYPT_CTXINFO_HASHVALUE, hash, &signatureLength), "getting attr hash"); // get the key and sign it CALL(cryptKeysetOpen (&cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, keyfilename, CRYPT_KEYOPT_READONLY), "opening key set"); CALL(cryptCreateContext(&sigKeyContext, CRYPT_UNUSED, CRYPT_ALGO_RSA), "creating RSA context"); sigKeyContext_initialized = true; CALL(cryptGetPrivateKey (cryptKeyset, &sigKeyContext, CRYPT_KEYID_NAME, "label", "password"), "getting key"); CALL(cryptCreateSignature (NULL, 0, &signatureLength, sigKeyContext, hashContext), "signing"); // check the signature to make sure it's right signature = (uchar *) calloc(1, signatureLength + 20); // second parameter is signatureMaxLength, so we allow a little more CALL(cryptCreateSignature (signature, signatureLength + 20, &signatureLength, sigKeyContext, hashContext), "signing"); // verify that the signature is right CALL(cryptCheckSignature (signature, signatureLength, sigKeyContext, hashContext), "verifying"); // end of protected block } while (0); // done with cryptlib, shut it down if (hashContext_initialized) { cryptDestroyContext(hashContext); hashContext_initialized = false; } if (sigKeyContext_initialized) { cryptDestroyContext(sigKeyContext); sigKeyContext_initialized = false; } // did we have any trouble above? if so, bail if (msg != 0) { return msg; } // ok, write the signature back to the object struct SignerInfo sigInfo; SignerInfo(&sigInfo, (ushort) 0); decode_casn(&sigInfo.self, signature); // were we supposed to make a bad signature? if so, make it bad if (bad) { uchar *sig; int siz = readvsize_casn(&sigInfo.signature, &sig); sig[0]++; write_casn(&sigInfo.signature, sig, siz); free(sig); } // copy the signature into the object copy_casn(&sigInfop->signature, &sigInfo.signature); delete_casn(&sigInfo.self); // all done with it now free(signature); // Mark it as encrypted with rsa, no params. // See http://www.ietf.org/mail-archive/web/sidr/current/msg04813.html for // why we use id_rsadsi_rsaEncryption instead of id_sha_256WithRSAEncryption // here. write_objid(&sigInfop->signatureAlgorithm.algorithm, id_rsadsi_rsaEncryption); write_casn(&sigInfop->signatureAlgorithm.parameters.self, (uchar *) "", 0); // no errors, we return NULL return NULL; }