static int SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert, PRBool encapsulated) { char digestdata[32]; unsigned int len; SECItem digest, data2sign; SEC_PKCS7ContentInfo *cinfo; SECStatus rv; if (outFile == NULL || inFile == NULL || cert == NULL) return -1; /* suck the file in */ if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE) != SECSuccess) return -1; if (!encapsulated) { /* unfortunately, we must create the digest ourselves */ /* SEC_PKCS7CreateSignedData should have a flag to not include */ /* the content for non-encapsulated content at encode time, but */ /* should always compute the hash itself */ if (CreateDigest(&data2sign, digestdata, &len, 32) < 0) return -1; digest.data = (unsigned char *)digestdata; digest.len = len; } /* XXX Need a better way to handle that usage stuff! */ cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL, SEC_OID_SHA1, encapsulated ? NULL : &digest, NULL, NULL); if (cinfo == NULL) return -1; if (encapsulated) { SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len); } rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return -1; } rv = SEC_PKCS7Encode (cinfo, SignOut, outFile, NULL, NULL, &pwdata); SEC_PKCS7DestroyContentInfo (cinfo); if (rv != SECSuccess) return -1; return 0; }
SEC_PKCS7ContentInfo * SECMIME_CreateSigned(CERTCertificate *scert, CERTCertificate *ecert, CERTCertDBHandle *certdb, SECOidTag digestalg, SECItem *digest, SECKEYGetPasswordKey pwfn, void *pwfn_arg) { SEC_PKCS7ContentInfo *cinfo; SECStatus rv; /* See note in header comment above about digestalg. */ /* Doesn't explain this. PORT_Assert (digestalg == SEC_OID_SHA1); */ cinfo = SEC_PKCS7CreateSignedData(scert, certUsageEmailSigner, certdb, digestalg, digest, pwfn, pwfn_arg); if (cinfo == NULL) return NULL; if (SEC_PKCS7IncludeCertChain(cinfo, NULL) != SECSuccess) { SEC_PKCS7DestroyContentInfo(cinfo); return NULL; } /* if the encryption cert and the signing cert differ, then include * the encryption cert too. */ /* it is ok to compare the pointers since we ref count, and the same * cert will always have the same pointer */ if ((ecert != NULL) && (ecert != scert)) { rv = SEC_PKCS7AddCertificate(cinfo, ecert); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo(cinfo); return NULL; } } /* * Add the signing time. But if it fails for some reason, * may as well not give up altogether -- just assert. */ rv = SEC_PKCS7AddSigningTime(cinfo); PORT_Assert(rv == SECSuccess); /* * Add the email profile. Again, if it fails for some reason, * may as well not give up altogether -- just assert. */ rv = smime_add_profile(ecert, cinfo); PORT_Assert(rv == SECSuccess); return cinfo; }
int jar_create_pk7(CERTCertDBHandle *certdb, void *keydb, CERTCertificate *cert, char *password, JAR_FILE infp, JAR_FILE outfp) { SEC_PKCS7ContentInfo *cinfo; const SECHashObject *hashObj; char *errstring; void *mw = NULL; void *hashcx; unsigned int len; int status = 0; SECStatus rv; SECItem digest; unsigned char digestdata[32]; unsigned char buffer[4096]; if (outfp == NULL || infp == NULL || cert == NULL) return JAR_ERR_GENERAL; /* we sign with SHA */ hashObj = HASH_GetHashObject(HASH_AlgSHA1); hashcx = (* hashObj->create)(); if (hashcx == NULL) return JAR_ERR_GENERAL; (* hashObj->begin)(hashcx); while (1) { int nb = JAR_FREAD(infp, buffer, sizeof buffer); if (nb == 0) { /* eof */ break; } (* hashObj->update) (hashcx, buffer, nb); } (* hashObj->end)(hashcx, digestdata, &len, 32); (* hashObj->destroy)(hashcx, PR_TRUE); digest.data = digestdata; digest.len = len; /* signtool must use any old context it can find since it's calling from inside javaland. */ PORT_SetError (0); cinfo = SEC_PKCS7CreateSignedData(cert, certUsageObjectSigner, NULL, SEC_OID_SHA1, &digest, NULL, mw); if (cinfo == NULL) return JAR_ERR_PK7; rv = SEC_PKCS7IncludeCertChain(cinfo, NULL); if (rv != SECSuccess) { status = PORT_GetError(); SEC_PKCS7DestroyContentInfo(cinfo); return status; } /* Having this here forces signtool to always include signing time. */ rv = SEC_PKCS7AddSigningTime(cinfo); /* don't check error */ PORT_SetError(0); /* if calling from mozilla thread*/ rv = SEC_PKCS7Encode(cinfo, jar_pk7_out, outfp, NULL, NULL, mw); if (rv != SECSuccess) status = PORT_GetError(); SEC_PKCS7DestroyContentInfo (cinfo); if (rv != SECSuccess) { errstring = JAR_get_error (status); return ((status < 0) ? status : JAR_ERR_GENERAL); } return 0; }
/********************************************************************** * * S i g n F i l e */ static int SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert) { int nb; char ibuf[4096], digestdata[32]; const SECHashObject *hashObj; void *hashcx; unsigned int len; SECItem digest; SEC_PKCS7ContentInfo * cinfo; SECStatus rv; if (outFile == NULL || inFile == NULL || cert == NULL) return - 1; /* XXX probably want to extend interface to allow other hash algorithms */ hashObj = HASH_GetHashObject(HASH_AlgSHA1); hashcx = (*hashObj->create)(); if (hashcx == NULL) return - 1; (*hashObj->begin)(hashcx); for (; ; ) { if (feof(inFile)) break; nb = fread(ibuf, 1, sizeof(ibuf), inFile); if (nb == 0) { if (ferror(inFile)) { PORT_SetError(SEC_ERROR_IO); (*hashObj->destroy)(hashcx, PR_TRUE); return - 1; } /* eof */ break; } (*hashObj->update)(hashcx, (unsigned char *) ibuf, nb); } (*hashObj->end)(hashcx, (unsigned char *) digestdata, &len, 32); (*hashObj->destroy)(hashcx, PR_TRUE); digest.data = (unsigned char *) digestdata; digest.len = len; cinfo = SEC_PKCS7CreateSignedData (cert, certUsageObjectSigner, NULL, SEC_OID_SHA1, &digest, NULL, NULL); if (cinfo == NULL) return - 1; rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return - 1; } if (no_time == 0) { rv = SEC_PKCS7AddSigningTime (cinfo); if (rv != SECSuccess) { /* don't check error */ } } rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, NULL, &pwdata); SEC_PKCS7DestroyContentInfo (cinfo); if (rv != SECSuccess) return - 1; return 0; }