| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| /* |
| * ocspresp - self test for OCSP response creation |
| */ |
| |
| #include "nspr.h" |
| #include "secutil.h" |
| #include "secpkcs7.h" |
| #include "cert.h" |
| #include "certdb.h" |
| #include "nss.h" |
| #include "pk11func.h" |
| #include "cryptohi.h" |
| #include "ocsp.h" |
| |
| #if defined(XP_UNIX) |
| #include <unistd.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| secuPWData pwdata = { PW_NONE, 0 }; |
| |
| static PRBool |
| getCaAndSubjectCert(CERTCertDBHandle *certHandle, |
| const char *caNick, const char *eeNick, |
| CERTCertificate **outCA, CERTCertificate **outCert) |
| { |
| *outCA = CERT_FindCertByNickname(certHandle, caNick); |
| *outCert = CERT_FindCertByNickname(certHandle, eeNick); |
| return *outCA && *outCert; |
| } |
| |
| static SECItem * |
| encode(PLArenaPool *arena, CERTOCSPCertID *cid, CERTCertificate *ca) |
| { |
| SECItem *response; |
| PRTime now = PR_Now(); |
| PRTime nextUpdate; |
| CERTOCSPSingleResponse **responses; |
| CERTOCSPSingleResponse *sr; |
| |
| if (!arena) |
| return NULL; |
| |
| nextUpdate = now + 10 * PR_USEC_PER_SEC; /* in the future */ |
| |
| sr = CERT_CreateOCSPSingleResponseGood(arena, cid, now, &nextUpdate); |
| |
| /* meaning of value 2: one entry + one end marker */ |
| responses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2); |
| if (responses == NULL) |
| return NULL; |
| |
| responses[0] = sr; |
| responses[1] = NULL; |
| |
| response = CERT_CreateEncodedOCSPSuccessResponse( |
| arena, ca, ocspResponderID_byName, now, responses, &pwdata); |
| |
| return response; |
| } |
| |
| static SECItem * |
| encodeRevoked(PLArenaPool *arena, CERTOCSPCertID *cid, CERTCertificate *ca) |
| { |
| SECItem *response; |
| PRTime now = PR_Now(); |
| PRTime revocationTime; |
| CERTOCSPSingleResponse **responses; |
| CERTOCSPSingleResponse *sr; |
| |
| if (!arena) |
| return NULL; |
| |
| revocationTime = now - 10 * PR_USEC_PER_SEC; /* in the past */ |
| |
| sr = CERT_CreateOCSPSingleResponseRevoked(arena, cid, now, NULL, |
| revocationTime, NULL); |
| |
| /* meaning of value 2: one entry + one end marker */ |
| responses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2); |
| if (responses == NULL) |
| return NULL; |
| |
| responses[0] = sr; |
| responses[1] = NULL; |
| |
| response = CERT_CreateEncodedOCSPSuccessResponse( |
| arena, ca, ocspResponderID_byName, now, responses, &pwdata); |
| |
| return response; |
| } |
| |
| int |
| Usage(void) |
| { |
| PRFileDesc *pr_stderr = PR_STDERR; |
| PR_fprintf(pr_stderr, "ocspresp runs an internal selftest for OCSP response creation"); |
| PR_fprintf(pr_stderr, "Usage:"); |
| PR_fprintf(pr_stderr, |
| "\tocspresp <dbdir> <CA-nick> <EE-nick> [-p <pass>] [-f <file>]\n"); |
| PR_fprintf(pr_stderr, |
| "\tdbdir: Find security databases in \"dbdir\"\n"); |
| PR_fprintf(pr_stderr, |
| "\tCA-nick: nickname of a trusted CA certificate with private key\n"); |
| PR_fprintf(pr_stderr, |
| "\tEE-nick: nickname of a entity cert issued by CA\n"); |
| PR_fprintf(pr_stderr, |
| "\t-p: a password for db\n"); |
| PR_fprintf(pr_stderr, |
| "\t-f: a filename containing the password for db\n"); |
| return -1; |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| SECStatus rv; |
| int retval = -1; |
| CERTCertDBHandle *certHandle = NULL; |
| CERTCertificate *caCert = NULL, *cert = NULL; |
| CERTOCSPCertID *cid = NULL; |
| PLArenaPool *arena = NULL; |
| PRTime now = PR_Now(); |
| |
| SECItem *encoded = NULL; |
| CERTOCSPResponse *decoded = NULL; |
| |
| SECItem *encodedRev = NULL; |
| CERTOCSPResponse *decodedRev = NULL; |
| |
| SECItem *encodedFail = NULL; |
| CERTOCSPResponse *decodedFail = NULL; |
| |
| CERTCertificate *obtainedSignerCert = NULL; |
| |
| if (argc != 4 && argc != 6) { |
| return Usage(); |
| } |
| |
| if (argc == 6) { |
| if (!strcmp(argv[4], "-p")) { |
| pwdata.source = PW_PLAINTEXT; |
| pwdata.data = PORT_Strdup(argv[5]); |
| } else if (!strcmp(argv[4], "-f")) { |
| pwdata.source = PW_FROMFILE; |
| pwdata.data = PORT_Strdup(argv[5]); |
| } else |
| return Usage(); |
| } |
| |
| PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
| /*rv = NSS_Init(SECU_ConfigDirectory(NULL));*/ |
| rv = NSS_Init(argv[1]); |
| if (rv != SECSuccess) { |
| SECU_PrintPRandOSError(argv[0]); |
| goto loser; |
| } |
| |
| PK11_SetPasswordFunc(SECU_GetModulePassword); |
| |
| certHandle = CERT_GetDefaultCertDB(); |
| if (!certHandle) |
| goto loser; |
| |
| if (!getCaAndSubjectCert(certHandle, argv[2], argv[3], &caCert, &cert)) |
| goto loser; |
| |
| cid = CERT_CreateOCSPCertID(cert, now); |
| |
| arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| encoded = encode(arena, cid, caCert); |
| PORT_Assert(encoded); |
| decoded = CERT_DecodeOCSPResponse(encoded); |
| PORT_CheckSuccess(CERT_GetOCSPResponseStatus(decoded)); |
| |
| PORT_CheckSuccess(CERT_VerifyOCSPResponseSignature(decoded, certHandle, &pwdata, |
| &obtainedSignerCert, caCert)); |
| PORT_CheckSuccess(CERT_GetOCSPStatusForCertID(certHandle, decoded, cid, |
| obtainedSignerCert, now)); |
| CERT_DestroyCertificate(obtainedSignerCert); |
| |
| encodedRev = encodeRevoked(arena, cid, caCert); |
| PORT_Assert(encodedRev); |
| decodedRev = CERT_DecodeOCSPResponse(encodedRev); |
| PORT_CheckSuccess(CERT_GetOCSPResponseStatus(decodedRev)); |
| |
| PORT_CheckSuccess(CERT_VerifyOCSPResponseSignature(decodedRev, certHandle, &pwdata, |
| &obtainedSignerCert, caCert)); |
| #ifdef DEBUG |
| { |
| rv = CERT_GetOCSPStatusForCertID(certHandle, decodedRev, cid, |
| obtainedSignerCert, now); |
| PORT_Assert(rv == SECFailure); |
| PORT_Assert(PORT_GetError() == SEC_ERROR_REVOKED_CERTIFICATE); |
| } |
| #else |
| (void)CERT_GetOCSPStatusForCertID(certHandle, decodedRev, cid, |
| obtainedSignerCert, now); |
| #endif |
| CERT_DestroyCertificate(obtainedSignerCert); |
| |
| encodedFail = CERT_CreateEncodedOCSPErrorResponse( |
| arena, SEC_ERROR_OCSP_TRY_SERVER_LATER); |
| PORT_Assert(encodedFail); |
| decodedFail = CERT_DecodeOCSPResponse(encodedFail); |
| #ifdef DEBUG |
| { |
| rv = CERT_GetOCSPResponseStatus(decodedFail); |
| PORT_Assert(rv == SECFailure); |
| PORT_Assert(PORT_GetError() == SEC_ERROR_OCSP_TRY_SERVER_LATER); |
| } |
| #else |
| (void)CERT_GetOCSPResponseStatus(decodedFail); |
| #endif |
| retval = 0; |
| loser: |
| if (retval != 0) |
| SECU_PrintError(argv[0], "tests failed"); |
| |
| if (cid) |
| CERT_DestroyOCSPCertID(cid); |
| if (cert) |
| CERT_DestroyCertificate(cert); |
| if (caCert) |
| CERT_DestroyCertificate(caCert); |
| if (arena) |
| PORT_FreeArena(arena, PR_FALSE); |
| if (decoded) |
| CERT_DestroyOCSPResponse(decoded); |
| if (decodedRev) |
| CERT_DestroyOCSPResponse(decodedRev); |
| if (decodedFail) |
| CERT_DestroyOCSPResponse(decodedFail); |
| if (pwdata.data) { |
| PORT_Free(pwdata.data); |
| } |
| |
| if (NSS_Shutdown() != SECSuccess) { |
| SECU_PrintError(argv[0], "NSS shutdown:"); |
| if (retval == 0) |
| retval = -2; |
| } |
| |
| return retval; |
| } |