diff options
Diffstat (limited to 'security/nss/lib/certhigh')
-rw-r--r-- | security/nss/lib/certhigh/Makefile | 80 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certhigh.c | 1203 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certhtml.c | 599 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certreq.c | 350 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certvfy.c | 2075 | ||||
-rw-r--r-- | security/nss/lib/certhigh/config.mk | 47 | ||||
-rw-r--r-- | security/nss/lib/certhigh/crlv2.c | 141 | ||||
-rw-r--r-- | security/nss/lib/certhigh/manifest.mn | 64 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocsp.c | 4179 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocsp.h | 549 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocspi.h | 47 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocspt.h | 293 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocspti.h | 408 | ||||
-rw-r--r-- | security/nss/lib/certhigh/xcrldist.c | 233 |
14 files changed, 0 insertions, 10268 deletions
diff --git a/security/nss/lib/certhigh/Makefile b/security/nss/lib/certhigh/Makefile deleted file mode 100644 index 7e0b30282..000000000 --- a/security/nss/lib/certhigh/Makefile +++ /dev/null @@ -1,80 +0,0 @@ -#! gmake -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Netscape security libraries. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -####################################################################### -# (1) Include initial platform-independent assignments (MANDATORY). # -####################################################################### - -include manifest.mn - -####################################################################### -# (2) Include "global" configuration information. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/config.mk - -####################################################################### -# (3) Include "component" configuration information. (OPTIONAL) # -####################################################################### - - - -####################################################################### -# (4) Include "local" platform-dependent assignments (OPTIONAL). # -####################################################################### - --include config.mk - -####################################################################### -# (5) Execute "global" rules. (OPTIONAL) # -####################################################################### - -include $(CORE_DEPTH)/coreconf/rules.mk - -####################################################################### -# (6) Execute "component" rules. (OPTIONAL) # -####################################################################### - - - -####################################################################### -# (7) Execute "local" rules. (OPTIONAL). # -####################################################################### - -export:: private_export - diff --git a/security/nss/lib/certhigh/certhigh.c b/security/nss/lib/certhigh/certhigh.c deleted file mode 100644 index ea7f50a0e..000000000 --- a/security/nss/lib/certhigh/certhigh.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#include "nspr.h" -#include "secerr.h" -#include "secasn1.h" -#include "seccomon.h" -#include "pk11func.h" -#include "certdb.h" -#include "certt.h" -#include "cert.h" -#include "certxutl.h" - -#ifndef NSS_3_4_CODE -#define NSS_3_4_CODE -#endif -#include "nsspki.h" -#include "pki.h" -#include "pkit.h" -#include "pkitm.h" -#include "pki3hack.h" - - -PRBool -CERT_MatchNickname(char *name1, char *name2) { - char *nickname1= NULL; - char *nickname2 = NULL; - char *token1; - char *token2; - char *token = NULL; - int len; - - /* first deal with the straight comparison */ - if (PORT_Strcmp(name1, name2) == 0) { - return PR_TRUE; - } - /* we need to handle the case where one name has an explicit token and the other - * doesn't */ - token1 = PORT_Strchr(name1,':'); - token2 = PORT_Strchr(name2,':'); - if ((token1 && token2) || (!token1 && !token2)) { - /* either both token names are specified or neither are, not match */ - return PR_FALSE; - } - if (token1) { - token=name1; - nickname1=token1; - nickname2=name2; - } else { - token=name2; - nickname1=token2; - nickname2=name1; - } - len = nickname1-token; - nickname1++; - if (PORT_Strcmp(nickname1,nickname2) != 0) { - return PR_FALSE; - } - /* compare the other token with the internal slot here */ - return PR_TRUE; -} - -/* - * Find all user certificates that match the given criteria. - * - * "handle" - database to search - * "usage" - certificate usage to match - * "oneCertPerName" - if set then only return the "best" cert per - * name - * "validOnly" - only return certs that are curently valid - * "proto_win" - window handle passed to pkcs11 - */ -CERTCertList * -CERT_FindUserCertsByUsage(CERTCertDBHandle *handle, - SECCertUsage usage, - PRBool oneCertPerName, - PRBool validOnly, - void *proto_win) -{ - CERTCertNicknames *nicknames = NULL; - char **nnptr; - int nn; - CERTCertificate *cert = NULL; - CERTCertList *certList = NULL; - SECStatus rv; - int64 time; - CERTCertListNode *node = NULL; - CERTCertListNode *freenode = NULL; - int n; - - time = PR_Now(); - - nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER, - proto_win); - - if ( ( nicknames == NULL ) || ( nicknames->numnicknames == 0 ) ) { - goto loser; - } - - nnptr = nicknames->nicknames; - nn = nicknames->numnicknames; - - while ( nn > 0 ) { - cert = NULL; - /* use the pk11 call so that we pick up any certs on tokens, - * which may require login - */ - if ( proto_win != NULL ) { - cert = PK11_FindCertFromNickname(*nnptr,proto_win); - } - - /* Sigh, It turns out if the cert is already in the temp db, because - * it's in the perm db, then the nickname lookup doesn't work. - * since we already have the cert here, though, than we can just call - * CERT_CreateSubjectCertList directly. For those cases where we didn't - * find the cert in pkcs #11 (because we didn't have a password arg, - * or because the nickname is for a peer, server, or CA cert, then we - * go look the cert up. - */ - if (cert == NULL) { - cert = CERT_FindCertByNickname(handle,*nnptr); - } - - if ( cert != NULL ) { - /* collect certs for this nickname, sorting them into the list */ - certList = CERT_CreateSubjectCertList(certList, handle, - &cert->derSubject, time, validOnly); - - CERT_FilterCertListForUserCerts(certList); - - /* drop the extra reference */ - CERT_DestroyCertificate(cert); - } - - nnptr++; - nn--; - } - - /* remove certs with incorrect usage */ - rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); - - if ( rv != SECSuccess ) { - goto loser; - } - - /* remove any extra certs for each name */ - if ( oneCertPerName ) { - PRBool *flags; - - nn = nicknames->numnicknames; - nnptr = nicknames->nicknames; - - flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn); - if ( flags == NULL ) { - goto loser; - } - - node = CERT_LIST_HEAD(certList); - - /* treverse all certs in the list */ - while ( !CERT_LIST_END(node, certList) ) { - - /* find matching nickname index */ - for ( n = 0; n < nn; n++ ) { - if ( CERT_MatchNickname(nnptr[n], node->cert->nickname) ) { - /* We found a match. If this is the first one, then - * set the flag and move on to the next cert. If this - * is not the first one then delete it from the list. - */ - if ( flags[n] ) { - /* We have already seen a cert with this nickname, - * so delete this one. - */ - freenode = node; - node = CERT_LIST_NEXT(node); - CERT_RemoveCertListNode(freenode); - } else { - /* keep the first cert for each nickname, but set the - * flag so we know to delete any others with the same - * nickname. - */ - flags[n] = PR_TRUE; - node = CERT_LIST_NEXT(node); - } - break; - } - } - if ( n == nn ) { - /* if we get here it means that we didn't find a matching - * nickname, which should not happen. - */ - PORT_Assert(0); - node = CERT_LIST_NEXT(node); - } - } - PORT_Free(flags); - } - - goto done; - -loser: - if ( certList != NULL ) { - CERT_DestroyCertList(certList); - certList = NULL; - } - -done: - if ( nicknames != NULL ) { - CERT_FreeNicknames(nicknames); - } - - return(certList); -} - -/* - * Find a user certificate that matchs the given criteria. - * - * "handle" - database to search - * "nickname" - nickname to match - * "usage" - certificate usage to match - * "validOnly" - only return certs that are curently valid - * "proto_win" - window handle passed to pkcs11 - */ -CERTCertificate * -CERT_FindUserCertByUsage(CERTCertDBHandle *handle, - char *nickname, - SECCertUsage usage, - PRBool validOnly, - void *proto_win) -{ - CERTCertificate *cert = NULL; - CERTCertList *certList = NULL; - SECStatus rv; - int64 time; - - time = PR_Now(); - - /* use the pk11 call so that we pick up any certs on tokens, - * which may require login - */ - /* XXX - why is this restricted? */ - if ( proto_win != NULL ) { - cert = PK11_FindCertFromNickname(nickname,proto_win); - } - - - /* sigh, There are still problems find smart cards from the temp - * db. This will get smart cards working again. The real fix - * is to make sure we can search the temp db by their token nickname. - */ - if (cert == NULL) { - cert = CERT_FindCertByNickname(handle,nickname); - } - - if ( cert != NULL ) { - /* collect certs for this nickname, sorting them into the list */ - certList = CERT_CreateSubjectCertList(certList, handle, - &cert->derSubject, time, validOnly); - - CERT_FilterCertListForUserCerts(certList); - - /* drop the extra reference */ - CERT_DestroyCertificate(cert); - cert = NULL; - } - - if ( certList == NULL ) { - goto loser; - } - - /* remove certs with incorrect usage */ - rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE); - - if ( rv != SECSuccess ) { - goto loser; - } - - if ( ! CERT_LIST_END(CERT_LIST_HEAD(certList), certList) ) { - cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert); - } - -loser: - if ( certList != NULL ) { - CERT_DestroyCertList(certList); - } - - return(cert); -} - -CERTCertList * -CERT_MatchUserCert(CERTCertDBHandle *handle, - SECCertUsage usage, - int nCANames, char **caNames, - void *proto_win) -{ - CERTCertList *certList = NULL; - SECStatus rv; - - certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE, - proto_win); - if ( certList == NULL ) { - goto loser; - } - - rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage); - if ( rv != SECSuccess ) { - goto loser; - } - - goto done; - -loser: - if ( certList != NULL ) { - CERT_DestroyCertList(certList); - certList = NULL; - } - -done: - - return(certList); -} - - -typedef struct stringNode { - struct stringNode *next; - char *string; -} stringNode; - -static PRStatus -CollectNicknames( NSSCertificate *c, void *data) -{ - CERTCertNicknames *names; - PRBool saveit = PR_FALSE; - stringNode *node; - int len; -#ifdef notdef - NSSTrustDomain *td; - NSSTrust *trust; -#endif - char *stanNickname; - char *nickname = NULL; - - names = (CERTCertNicknames *)data; - - stanNickname = nssCertificate_GetNickname(c,NULL); - - if ( stanNickname ) { - if (names->what == SEC_CERT_NICKNAMES_USER) { - saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL); - } -#ifdef notdef - else { - td = NSSCertificate_GetTrustDomain(c); - if (!td) { - return PR_SUCCESS; - } - trust = nssTrustDomain_FindTrustForCertificate(td,c); - - switch(names->what) { - case SEC_CERT_NICKNAMES_ALL: - if ((trust->sslFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || - (trust->emailFlags & (CERTDB_VALID_CA|CERTDB_VALID_PEER) ) || - (trust->objectSigningFlags & - (CERTDB_VALID_CA|CERTDB_VALID_PEER))) { - saveit = PR_TRUE; - } - - break; - case SEC_CERT_NICKNAMES_SERVER: - if ( trust->sslFlags & CERTDB_VALID_PEER ) { - saveit = PR_TRUE; - } - - break; - case SEC_CERT_NICKNAMES_CA: - if (((trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA)|| - ((trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA) || - ((trust->objectSigningFlags & CERTDB_VALID_CA ) - == CERTDB_VALID_CA)) { - saveit = PR_TRUE; - } - break; - } - } -#endif - } - - /* traverse the list of collected nicknames and make sure we don't make - * a duplicate - */ - if ( saveit ) { - nickname = STAN_GetCERTCertificateName(NULL, c); - /* nickname can only be NULL here if we are having memory - * alloc problems */ - if (nickname == NULL) { - return PR_FAILURE; - } - node = (stringNode *)names->head; - while ( node != NULL ) { - if ( PORT_Strcmp(nickname, node->string) == 0 ) { - /* if the string matches, then don't save this one */ - saveit = PR_FALSE; - break; - } - node = node->next; - } - } - - if ( saveit ) { - - /* allocate the node */ - node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode)); - if ( node == NULL ) { - PORT_Free(nickname); - return PR_FAILURE; - } - - /* copy the string */ - len = PORT_Strlen(nickname) + 1; - node->string = (char*)PORT_ArenaAlloc(names->arena, len); - if ( node->string == NULL ) { - PORT_Free(nickname); - return PR_FAILURE; - } - PORT_Memcpy(node->string, nickname, len); - - /* link it into the list */ - node->next = (stringNode *)names->head; - names->head = (void *)node; - - /* bump the count */ - names->numnicknames++; - } - - if (nickname) PORT_Free(nickname); - return(PR_SUCCESS); -} - -CERTCertNicknames * -CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx) -{ - PRArenaPool *arena; - CERTCertNicknames *names; - int i; - stringNode *node; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( arena == NULL ) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return(NULL); - } - - names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); - if ( names == NULL ) { - goto loser; - } - - names->arena = arena; - names->head = NULL; - names->numnicknames = 0; - names->nicknames = NULL; - names->what = what; - names->totallen = 0; - - /* make sure we are logged in */ - (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx); - - NSSTrustDomain_TraverseCertificates(handle, - CollectNicknames, (void *)names); - if ( names->numnicknames ) { - names->nicknames = (char**)PORT_ArenaAlloc(arena, - names->numnicknames * sizeof(char *)); - - if ( names->nicknames == NULL ) { - goto loser; - } - - node = (stringNode *)names->head; - - for ( i = 0; i < names->numnicknames; i++ ) { - PORT_Assert(node != NULL); - - names->nicknames[i] = node->string; - names->totallen += PORT_Strlen(node->string); - node = node->next; - } - - PORT_Assert(node == NULL); - } - - return(names); - -loser: - PORT_FreeArena(arena, PR_FALSE); - return(NULL); -} - -void -CERT_FreeNicknames(CERTCertNicknames *nicknames) -{ - PORT_FreeArena(nicknames->arena, PR_FALSE); - - return; -} - -/* [ FROM pcertdb.c ] */ - -typedef struct dnameNode { - struct dnameNode *next; - SECItem name; -} dnameNode; - -void -CERT_FreeDistNames(CERTDistNames *names) -{ - PORT_FreeArena(names->arena, PR_FALSE); - - return; -} - -static SECStatus -CollectDistNames( CERTCertificate *cert, SECItem *k, void *data) -{ - CERTDistNames *names; - PRBool saveit = PR_FALSE; - CERTCertTrust *trust; - dnameNode *node; - int len; - - names = (CERTDistNames *)data; - - if ( cert->trust ) { - trust = cert->trust; - - /* only collect names of CAs trusted for issuing SSL clients */ - if ( trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ) { - saveit = PR_TRUE; - } - } - - if ( saveit ) { - /* allocate the node */ - node = (dnameNode*)PORT_ArenaAlloc(names->arena, sizeof(dnameNode)); - if ( node == NULL ) { - return(SECFailure); - } - - /* copy the name */ - node->name.len = len = cert->derSubject.len; - node->name.type = siBuffer; - node->name.data = (unsigned char*)PORT_ArenaAlloc(names->arena, len); - if ( node->name.data == NULL ) { - return(SECFailure); - } - PORT_Memcpy(node->name.data, cert->derSubject.data, len); - - /* link it into the list */ - node->next = (dnameNode *)names->head; - names->head = (void *)node; - - /* bump the count */ - names->nnames++; - } - - return(SECSuccess); -} - -/* - * Return all of the CAs that are "trusted" for SSL. - */ -CERTDistNames * -CERT_GetSSLCACerts(CERTCertDBHandle *handle) -{ - PRArenaPool *arena; - CERTDistNames *names; - int i; - SECStatus rv; - dnameNode *node; - - /* allocate an arena to use */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( arena == NULL ) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return(NULL); - } - - /* allocate the header structure */ - names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames)); - if ( names == NULL ) { - goto loser; - } - - /* initialize the header struct */ - names->arena = arena; - names->head = NULL; - names->nnames = 0; - names->names = NULL; - - /* collect the names from the database */ - rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL); - if ( rv ) { - goto loser; - } - - /* construct the array from the list */ - if ( names->nnames ) { - names->names = (SECItem*)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem)); - - if ( names->names == NULL ) { - goto loser; - } - - node = (dnameNode *)names->head; - - for ( i = 0; i < names->nnames; i++ ) { - PORT_Assert(node != NULL); - - names->names[i] = node->name; - node = node->next; - } - - PORT_Assert(node == NULL); - } - - return(names); - -loser: - PORT_FreeArena(arena, PR_FALSE); - return(NULL); -} - -CERTDistNames * -CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames, - int nnames) -{ - CERTDistNames *dnames = NULL; - PRArenaPool *arena; - int i, rv; - SECItem *names = NULL; - CERTCertificate *cert = NULL; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) goto loser; - dnames = PORT_ArenaZNew(arena, CERTDistNames); - if (dnames == NULL) goto loser; - - dnames->arena = arena; - dnames->nnames = nnames; - dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames); - if (names == NULL) goto loser; - - for (i = 0; i < nnames; i++) { - cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]); - if (cert == NULL) goto loser; - rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject); - if (rv == SECFailure) goto loser; - CERT_DestroyCertificate(cert); - } - return dnames; - -loser: - if (cert != NULL) - CERT_DestroyCertificate(cert); - if (arena != NULL) - PORT_FreeArena(arena, PR_FALSE); - return NULL; -} - -/* [ from pcertdb.c - calls Ascii to Name ] */ -/* - * Lookup a certificate in the database by name - */ -CERTCertificate * -CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) -{ - CERTName *name; - SECItem *nameItem; - CERTCertificate *cert = NULL; - PRArenaPool *arena = NULL; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - - if ( arena == NULL ) { - goto loser; - } - - name = CERT_AsciiToName(nameStr); - - if ( name ) { - nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name, - CERT_NameTemplate); - if ( nameItem != NULL ) { - cert = CERT_FindCertByName(handle, nameItem); - } - CERT_DestroyName(name); - } - -loser: - if ( arena ) { - PORT_FreeArena(arena, PR_FALSE); - } - - return(cert); -} - -/* From certv3.c */ - -CERTCrlDistributionPoints * -CERT_FindCRLDistributionPoints (CERTCertificate *cert) -{ - SECItem encodedExtenValue; - SECStatus rv; - CERTCrlDistributionPoints *dps; - - encodedExtenValue.data = NULL; - encodedExtenValue.len = 0; - - rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS, - &encodedExtenValue); - if ( rv != SECSuccess ) { - return (NULL); - } - - dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue); - - PORT_Free(encodedExtenValue.data); - - return dps; -} - -/* From crl.c */ -CERTSignedCrl * CERT_ImportCRL - (CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx) -{ - CERTSignedCrl* retCrl = NULL; - PK11SlotInfo* slot = PK11_GetInternalKeySlot(); - retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx, - CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS); - PK11_FreeSlot(slot); - - return retCrl; -} - -/* From certdb.c */ -static SECStatus -cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted) -{ - SECStatus rv; - SECItem *derCert; - CERTCertificate *cert = NULL; - CERTCertificate *newcert = NULL; - CERTCertDBHandle *handle; - CERTCertTrust trust; - PRBool isca; - char *nickname; - unsigned int certtype; - - handle = CERT_GetDefaultCertDB(); - - while (numcerts--) { - derCert = certs; - certs++; - - /* decode my certificate */ - /* This use is ok -- only looks at decoded parts, calls NewTemp later */ - newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); - if ( newcert == NULL ) { - goto loser; - } - - if (!trusted) { - /* make sure that cert is valid */ - rv = CERT_CertTimesValid(newcert); - if ( rv == SECFailure ) { - goto endloop; - } - } - - /* does it have the CA extension */ - - /* - * Make sure that if this is an intermediate CA in the chain that - * it was given permission by its signer to be a CA. - */ - isca = CERT_IsCACert(newcert, &certtype); - - if ( !isca ) { - if (!trusted) { - goto endloop; - } - trust.sslFlags = CERTDB_VALID_CA; - trust.emailFlags = CERTDB_VALID_CA; - trust.objectSigningFlags = CERTDB_VALID_CA; - } else { - /* SSL ca's must have the ssl bit set */ - if ( ( certUsage == certUsageSSLCA ) && - (( certtype & NS_CERT_TYPE_SSL_CA ) != NS_CERT_TYPE_SSL_CA )) { - goto endloop; - } - - /* it passed all of the tests, so lets add it to the database */ - /* mark it as a CA */ - PORT_Memset((void *)&trust, 0, sizeof(trust)); - switch ( certUsage ) { - case certUsageSSLCA: - trust.sslFlags = CERTDB_VALID_CA; - break; - case certUsageUserCertImport: - if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { - trust.sslFlags = CERTDB_VALID_CA; - } - if ((certtype & NS_CERT_TYPE_EMAIL_CA) - == NS_CERT_TYPE_EMAIL_CA ) { - trust.emailFlags = CERTDB_VALID_CA; - } - if ( ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) == - NS_CERT_TYPE_OBJECT_SIGNING_CA ) { - trust.objectSigningFlags = CERTDB_VALID_CA; - } - break; - default: - PORT_Assert(0); - break; - } - } - - cert = CERT_NewTempCertificate(handle, derCert, NULL, - PR_FALSE, PR_FALSE); - if ( cert == NULL ) { - goto loser; - } - - /* if the cert is temp, make it perm; otherwise we're done */ - if (cert->istemp) { - /* get a default nickname for it */ - nickname = CERT_MakeCANickname(cert); - - rv = CERT_AddTempCertToPerm(cert, nickname, &trust); - - /* free the nickname */ - if ( nickname ) { - PORT_Free(nickname); - } - } else { - rv = SECSuccess; - } - - CERT_DestroyCertificate(cert); - cert = NULL; - - if ( rv != SECSuccess ) { - goto loser; - } - -endloop: - if ( newcert ) { - CERT_DestroyCertificate(newcert); - newcert = NULL; - } - - } - - rv = SECSuccess; - goto done; -loser: - rv = SECFailure; -done: - - if ( newcert ) { - CERT_DestroyCertificate(newcert); - newcert = NULL; - } - - if ( cert ) { - CERT_DestroyCertificate(cert); - cert = NULL; - } - - return(rv); -} - -SECStatus -CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage) -{ - return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE); -} - -SECStatus -CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage) { - return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE); -} - -/* Moved from certdb.c */ -/* -** CERT_CertChainFromCert -** -** Construct a CERTCertificateList consisting of the given certificate and all -** of the issuer certs until we either get to a self-signed cert or can't find -** an issuer. Since we don't know how many certs are in the chain we have to -** build a linked list first as we count them. -*/ - -typedef struct certNode { - struct certNode *next; - CERTCertificate *cert; -} certNode; - -CERTCertificateList * -CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage, - PRBool includeRoot) -{ -#ifdef NSS_CLASSIC - CERTCertificateList *chain = NULL; - CERTCertificate *c; - SECItem *p; - int rv, len = 0; - PRArenaPool *tmpArena, *arena; - certNode *head, *tail, *node; - - /* - * Initialize stuff so we can goto loser. - */ - head = NULL; - arena = NULL; - - /* arena for linked list */ - tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (tmpArena == NULL) goto no_memory; - - /* arena for SecCertificateList */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) goto no_memory; - - head = tail = (certNode*)PORT_ArenaZAlloc(tmpArena, sizeof(certNode)); - if (head == NULL) goto no_memory; - - /* put primary cert first in the linked list */ - head->cert = c = CERT_DupCertificate(cert); - if (head->cert == NULL) goto loser; - len++; - - /* add certs until we come to a self-signed one */ - while(SECITEM_CompareItem(&c->derIssuer, &c->derSubject) != SECEqual) { - c = CERT_FindCertIssuer(tail->cert, PR_Now(), usage); - if (c == NULL) { - /* no root is found, so make sure we don't attempt to delete one - * below - */ - includeRoot = PR_TRUE; - break; - } - - tail->next = (certNode*)PORT_ArenaZAlloc(tmpArena, sizeof(certNode)); - tail = tail->next; - if (tail == NULL) goto no_memory; - - tail->cert = c; - len++; - } - - /* now build the CERTCertificateList */ - chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)); - if (chain == NULL) goto no_memory; - chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); - if (chain->certs == NULL) goto no_memory; - - for(node = head, p = chain->certs; node; node = node->next, p++) { - rv = SECITEM_CopyItem(arena, p, &node->cert->derCert); - CERT_DestroyCertificate(node->cert); - node->cert = NULL; - if (rv < 0) goto loser; - } - if ( !includeRoot && len > 1) { - chain->len = len - 1; - } else { - chain->len = len; - } - - chain->arena = arena; - - PORT_FreeArena(tmpArena, PR_FALSE); - - return chain; - -no_memory: - PORT_SetError(SEC_ERROR_NO_MEMORY); -loser: - if (head != NULL) { - for (node = head; node; node = node->next) { - if (node->cert != NULL) - CERT_DestroyCertificate(node->cert); - } - } - - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - - if (tmpArena != NULL) { - PORT_FreeArena(tmpArena, PR_FALSE); - } - - return NULL; -#else - CERTCertificateList *chain = NULL; - NSSCertificate **stanChain; - NSSCertificate *stanCert; - PRArenaPool *arena; - NSSUsage nssUsage; - int i, len; - NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); - NSSCryptoContext *cc = STAN_GetDefaultCryptoContext(); - - stanCert = STAN_GetNSSCertificate(cert); - nssUsage.anyUsage = PR_FALSE; - nssUsage.nss3usage = usage; - nssUsage.nss3lookingForCA = PR_FALSE; - stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, - NULL, 0, NULL, NULL, td, cc); - if (!stanChain) { - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - return NULL; - } - - len = 0; - stanCert = stanChain[0]; - while (stanCert) { - stanCert = stanChain[++len]; - } - - arena = PORT_NewArena(4096); - if (arena == NULL) { - goto loser; - } - - chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, - sizeof(CERTCertificateList)); - if (!chain) goto loser; - chain->certs = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); - if (!chain->certs) goto loser; - i = 0; - stanCert = stanChain[i]; - while (stanCert) { - SECItem derCert; - CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); - if (!cCert) { - goto loser; - } - derCert.len = (unsigned int)stanCert->encoding.size; - derCert.data = (unsigned char *)stanCert->encoding.data; - derCert.type = siBuffer; - SECITEM_CopyItem(arena, &chain->certs[i], &derCert); - stanCert = stanChain[++i]; - if (!stanCert && !cCert->isRoot) { - /* reached the end of the chain, but the final cert is - * not a root. Don't discard it. - */ - includeRoot = PR_TRUE; - } - CERT_DestroyCertificate(cCert); - } - if ( !includeRoot && len > 1) { - chain->len = len - 1; - } else { - chain->len = len; - } - - chain->arena = arena; - nss_ZFreeIf(stanChain); - return chain; -loser: - i = 0; - stanCert = stanChain[i]; - while (stanCert) { - CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert); - if (cCert) { - CERT_DestroyCertificate(cCert); - } - stanCert = stanChain[++i]; - } - nss_ZFreeIf(stanChain); - if (arena) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -#endif -} - -/* Builds a CERTCertificateList holding just one DER-encoded cert, namely -** the one for the cert passed as an argument. -*/ -CERTCertificateList * -CERT_CertListFromCert(CERTCertificate *cert) -{ - CERTCertificateList *chain = NULL; - int rv; - PRArenaPool *arena; - - /* arena for SecCertificateList */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) goto no_memory; - - /* build the CERTCertificateList */ - chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList)); - if (chain == NULL) goto no_memory; - chain->certs = (SECItem*)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem)); - if (chain->certs == NULL) goto no_memory; - rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert)); - if (rv < 0) goto loser; - chain->len = 1; - chain->arena = arena; - - return chain; - -no_memory: - PORT_SetError(SEC_ERROR_NO_MEMORY); -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -} - -CERTCertificateList * -CERT_DupCertList(CERTCertificateList * oldList) -{ - CERTCertificateList *newList = NULL; - PRArenaPool *arena = NULL; - SECItem *newItem; - SECItem *oldItem; - int len = oldList->len; - int rv; - - /* arena for SecCertificateList */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) - goto no_memory; - - /* now build the CERTCertificateList */ - newList = PORT_ArenaNew(arena, CERTCertificateList); - if (newList == NULL) - goto no_memory; - newList->arena = arena; - newItem = (SECItem*)PORT_ArenaAlloc(arena, len * sizeof(SECItem)); - if (newItem == NULL) - goto no_memory; - newList->certs = newItem; - newList->len = len; - - for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) { - rv = SECITEM_CopyItem(arena, newItem, oldItem); - if (rv < 0) - goto loser; - } - return newList; - -no_memory: - PORT_SetError(SEC_ERROR_NO_MEMORY); -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -} - -void -CERT_DestroyCertificateList(CERTCertificateList *list) -{ - PORT_FreeArena(list->arena, PR_FALSE); -} - diff --git a/security/nss/lib/certhigh/certhtml.c b/security/nss/lib/certhigh/certhtml.c deleted file mode 100644 index 11ce4f6c8..000000000 --- a/security/nss/lib/certhigh/certhtml.c +++ /dev/null @@ -1,599 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * certhtml.c --- convert a cert to html - * - * $Id$ - */ - -#include "seccomon.h" -#include "secitem.h" -#include "sechash.h" -#include "cert.h" -#include "keyhi.h" -#include "secder.h" -#include "prprf.h" -#include "secport.h" -#include "secasn1.h" -#include "pk11func.h" - -static char *hex = "0123456789ABCDEF"; - -/* -** Convert a der-encoded integer to a hex printable string form -*/ -char *CERT_Hexify (SECItem *i, int do_colon) -{ - unsigned char *cp, *end; - char *rv, *o; - - if (!i->len) { - return PORT_Strdup("00"); - } - - rv = o = (char*) PORT_Alloc(i->len * 3); - if (!rv) return rv; - - cp = i->data; - end = cp + i->len; - while (cp < end) { - unsigned char ch = *cp++; - *o++ = hex[(ch >> 4) & 0xf]; - *o++ = hex[ch & 0xf]; - if (cp != end) { - if (do_colon) { - *o++ = ':'; - } - } - } - *o = 0; /* Null terminate the string */ - return rv; -} - -static char * -gatherStrings(char **strings) -{ - char **strs; - int len; - char *ret; - char *s; - - /* find total length of all strings */ - strs = strings; - len = 0; - while ( *strs ) { - len += PORT_Strlen(*strs); - strs++; - } - - /* alloc enough memory for it */ - ret = (char*)PORT_Alloc(len + 1); - if ( !ret ) { - return(ret); - } - - s = ret; - - /* copy the strings */ - strs = strings; - while ( *strs ) { - PORT_Strcpy(s, *strs); - s += PORT_Strlen(*strs); - strs++; - } - - return( ret ); -} - -#define BREAK "<br>" -#define BREAKLEN 4 -#define COMMA ", " -#define COMMALEN 2 - -#define MAX_OUS 20 -#define MAX_DC MAX_OUS - - -char *CERT_FormatName (CERTName *name) -{ - CERTRDN** rdns; - CERTRDN * rdn; - CERTAVA** avas; - CERTAVA* ava; - char * buf = 0; - char * tmpbuf = 0; - SECItem * cn = 0; - SECItem * email = 0; - SECItem * org = 0; - SECItem * loc = 0; - SECItem * state = 0; - SECItem * country = 0; - SECItem * dq = 0; - - unsigned len = 0; - int tag; - int i; - int ou_count = 0; - int dc_count = 0; - PRBool first; - SECItem * orgunit[MAX_OUS]; - SECItem * dc[MAX_DC]; - - /* Loop over name components and gather the interesting ones */ - rdns = name->rdns; - while ((rdn = *rdns++) != 0) { - avas = rdn->avas; - while ((ava = *avas++) != 0) { - tag = CERT_GetAVATag(ava); - switch(tag) { - case SEC_OID_AVA_COMMON_NAME: - cn = CERT_DecodeAVAValue(&ava->value); - len += cn->len; - break; - case SEC_OID_AVA_COUNTRY_NAME: - country = CERT_DecodeAVAValue(&ava->value); - len += country->len; - break; - case SEC_OID_AVA_LOCALITY: - loc = CERT_DecodeAVAValue(&ava->value); - len += loc->len; - break; - case SEC_OID_AVA_STATE_OR_PROVINCE: - state = CERT_DecodeAVAValue(&ava->value); - len += state->len; - break; - case SEC_OID_AVA_ORGANIZATION_NAME: - org = CERT_DecodeAVAValue(&ava->value); - len += org->len; - break; - case SEC_OID_AVA_DN_QUALIFIER: - dq = CERT_DecodeAVAValue(&ava->value); - len += dq->len; - break; - case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: - if (ou_count < MAX_OUS) { - orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value); - len += orgunit[ou_count++]->len; - } - break; - case SEC_OID_AVA_DC: - if (dc_count < MAX_DC) { - dc[dc_count] = CERT_DecodeAVAValue(&ava->value); - len += dc[dc_count++]->len; - } - break; - case SEC_OID_PKCS9_EMAIL_ADDRESS: - case SEC_OID_RFC1274_MAIL: - email = CERT_DecodeAVAValue(&ava->value); - len += email->len; - break; - default: - break; - } - } - } - - /* XXX - add some for formatting */ - len += 128; - - /* allocate buffer */ - buf = (char *)PORT_Alloc(len); - if ( !buf ) { - return(0); - } - - tmpbuf = buf; - - if ( cn ) { - PORT_Memcpy(tmpbuf, cn->data, cn->len); - tmpbuf += cn->len; - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(cn, PR_TRUE); - } - if ( email ) { - PORT_Memcpy(tmpbuf, email->data, email->len); - tmpbuf += ( email->len ); - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(email, PR_TRUE); - } - for (i=ou_count-1; i >= 0; i--) { - PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len); - tmpbuf += ( orgunit[i]->len ); - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(orgunit[i], PR_TRUE); - } - if ( dq ) { - PORT_Memcpy(tmpbuf, dq->data, dq->len); - tmpbuf += ( dq->len ); - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(dq, PR_TRUE); - } - if ( org ) { - PORT_Memcpy(tmpbuf, org->data, org->len); - tmpbuf += ( org->len ); - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(org, PR_TRUE); - } - for (i=dc_count-1; i >= 0; i--) { - PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len); - tmpbuf += ( dc[i]->len ); - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - SECITEM_FreeItem(dc[i], PR_TRUE); - } - first = PR_TRUE; - if ( loc ) { - PORT_Memcpy(tmpbuf, loc->data, loc->len); - tmpbuf += ( loc->len ); - first = PR_FALSE; - SECITEM_FreeItem(loc, PR_TRUE); - } - if ( state ) { - if ( !first ) { - PORT_Memcpy(tmpbuf, COMMA, COMMALEN); - tmpbuf += COMMALEN; - } - PORT_Memcpy(tmpbuf, state->data, state->len); - tmpbuf += ( state->len ); - first = PR_FALSE; - SECITEM_FreeItem(state, PR_TRUE); - } - if ( country ) { - if ( !first ) { - PORT_Memcpy(tmpbuf, COMMA, COMMALEN); - tmpbuf += COMMALEN; - } - PORT_Memcpy(tmpbuf, country->data, country->len); - tmpbuf += ( country->len ); - first = PR_FALSE; - SECITEM_FreeItem(country, PR_TRUE); - } - if ( !first ) { - PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); - tmpbuf += BREAKLEN; - } - - *tmpbuf = 0; - - return(buf); -} - -static char *sec_FortezzaClearance(SECItem *clearance) { - unsigned char clr = 0; - - if (clearance->len > 0) { clr = clearance->data[0]; } - - if (clr & 0x4) return "Top Secret"; - if (clr & 0x8) return "Secret"; - if (clr & 0x10) return "Confidential"; - if (clr & 0x20) return "Sensitive"; - if (clr & 0x40) return "Unclassified"; - return "None"; -} - -static char *sec_FortezzaMessagePrivilege(SECItem *priv) { - unsigned char clr = 0; - - if (priv->len > 0) { clr = (priv->data[0]) & 0x78; } - - if (clr == 0x00) { - return "None"; - } else { - - return PR_smprintf("%s%s%s%s%s%s%s", - - clr&0x40?"Critical/Flash":"", - (clr&0x40) && (clr&0x38) ? ", " : "" , - - clr&0x20?"Immediate/Priority":"", - (clr&0x20) && (clr&0x18) ? ", " : "" , - - clr&0x10?"Routine/Deferred":"", - (clr&0x10) && (clr&0x08) ? ", " : "" , - - clr&0x08?"Rekey Agent":""); - } - -} - -static char *sec_FortezzaCertPrivilege(SECItem *priv) { - unsigned char clr = 0; - - if (priv->len > 0) { clr = priv->data[0]; } - - return PR_smprintf("%s%s%s%s%s%s%s%s%s%s%s%s", - clr&0x40?"Organizational Releaser":"", - (clr&0x40) && (clr&0x3e) ? "," : "" , - clr&0x20?"Policy Creation Authority":"", - (clr&0x20) && (clr&0x1e) ? "," : "" , - clr&0x10?"Certificate Authority":"", - (clr&0x10) && (clr&0x0e) ? "," : "" , - clr&0x08?"Local Managment Authority":"", - (clr&0x08) && (clr&0x06) ? "," : "" , - clr&0x04?"Configuration Vector Authority":"", - (clr&0x04) && (clr&0x02) ? "," : "" , - clr&0x02?"No Signature Capability":"", - clr&0x7e?"":"Signing Only" - ); -} - -static char *htmlcertstrings[] = { - "<table border=0 cellspacing=0 cellpadding=0><tr><td valign=top>" - "<font size=2><b>This Certificate belongs to:</b><br>" - "<table border=0 cellspacing=0 cellpadding=0><tr><td>", - 0, /* image goes here */ - 0, - 0, - "</td><td width=10> </td><td><font size=2>", - 0, /* subject name goes here */ - "</td></tr></table></font></td><td width=20> </td><td valign=top>" - "<font size=2><b>This Certificate was issued by:</b><br>" - "<table border=0 cellspacing=0 cellpadding=0><tr><td>", - 0, /* image goes here */ - 0, - 0, - "</td><td width=10> </td><td><font size=2>", - 0, /* issuer name goes here */ - "</td></tr></table></font></td></tr></table>" - "<b>Serial Number:</b> ", - 0, - "<br><b>This Certificate is valid from ", - 0, /* notBefore goes here */ - " to ", - 0, /* notAfter does here */ - "</b><br><b>Clearance:</b>", - 0, - "<br><b>DSS Privileges:</b>", - 0, - "<br><b>KEA Privileges:</b>", - 0, - "<br><b>KMID:</b>", - 0, - "<br><b>Certificate Fingerprint:</b>" - "<table border=0 cellspacing=0 cellpadding=0><tr>" - "<td width=10> </td><td><font size=2>", - 0, /* fingerprint goes here */ - "</td></tr></table>", - 0, /* comment header goes here */ - 0, /* comment goes here */ - 0, /* comment trailer goes here */ - 0 -}; - -char * -CERT_HTMLCertInfo(CERTCertificate *cert, PRBool showImages, PRBool showIssuer) -{ - SECStatus rv; - char *issuer, *subject, *serialNumber, *version; - char *notBefore, *notAfter; - char *ret; - char *nickname; - unsigned char fingerprint[16]; /* result of MD5, always 16 bytes */ - char *fpstr; - SECItem fpitem; - char *commentstring = NULL; - SECKEYPublicKey *pubk; - char *DSSPriv; - char *KMID = NULL; - char *servername; - - if (!cert) { - return(0); - } - - issuer = CERT_FormatName (&cert->issuer); - subject = CERT_FormatName (&cert->subject); - version = CERT_Hexify (&cert->version,1); - serialNumber = CERT_Hexify (&cert->serialNumber,1); - notBefore = DER_TimeChoiceDayToAscii(&cert->validity.notBefore); - notAfter = DER_TimeChoiceDayToAscii(&cert->validity.notAfter); - servername = CERT_FindNSStringExtension(cert, - SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME); - - nickname = cert->nickname; - if ( nickname == NULL ) { - showImages = PR_FALSE; - } - - rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SUBJECT_LOGO, - NULL); - - if ( rv || !showImages ) { - htmlcertstrings[1] = ""; - htmlcertstrings[2] = ""; - htmlcertstrings[3] = ""; - } else { - htmlcertstrings[1] = "<img src=\"about:security?subject-logo="; - htmlcertstrings[2] = nickname; - htmlcertstrings[3] = "\">"; - } - - if ( servername ) { - char *tmpstr; - tmpstr = (char *)PORT_Alloc(PORT_Strlen(subject) + - PORT_Strlen(servername) + - sizeof("<br>") + 1); - if ( tmpstr ) { - PORT_Strcpy(tmpstr, servername); - PORT_Strcat(tmpstr, "<br>"); - PORT_Strcat(tmpstr, subject); - PORT_Free(subject); - subject = tmpstr; - } - } - - htmlcertstrings[5] = subject; - - rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_ISSUER_LOGO, - NULL); - - if ( rv || !showImages ) { - htmlcertstrings[7] = ""; - htmlcertstrings[8] = ""; - htmlcertstrings[9] = ""; - } else { - htmlcertstrings[7] = "<img src=\"about:security?issuer-logo="; - htmlcertstrings[8] = nickname; - htmlcertstrings[9] = "\">"; - } - - - if (showIssuer == PR_TRUE) { - htmlcertstrings[11] = issuer; - } else { - htmlcertstrings[11] = ""; - } - - htmlcertstrings[13] = serialNumber; - htmlcertstrings[15] = notBefore; - htmlcertstrings[17] = notAfter; - - pubk = CERT_ExtractPublicKey(cert); - DSSPriv = NULL; - if (pubk && (pubk->keyType == fortezzaKey)) { - SECItem dummyitem; - htmlcertstrings[18] = "</b><br><b>Clearance:</b>"; - htmlcertstrings[19] = sec_FortezzaClearance( - &pubk->u.fortezza.clearance); - htmlcertstrings[20] = "<br><b>DSS Privileges:</b>"; - DSSPriv = sec_FortezzaCertPrivilege( - &pubk->u.fortezza.DSSpriviledge); - htmlcertstrings[21] = DSSPriv; - htmlcertstrings[22] = "<br><b>KEA Privileges:</b>"; - htmlcertstrings[23] = sec_FortezzaMessagePrivilege( - &pubk->u.fortezza.KEApriviledge); - htmlcertstrings[24] = "<br><b>KMID:</b>"; - dummyitem.data = &pubk->u.fortezza.KMID[0]; - dummyitem.len = sizeof(pubk->u.fortezza.KMID); - KMID = CERT_Hexify (&dummyitem,0); - htmlcertstrings[25] = KMID; - } else { - /* clear out the headers in the non-fortezza cases */ - htmlcertstrings[18] = ""; - htmlcertstrings[19] = ""; - htmlcertstrings[20] = ""; - htmlcertstrings[21] = ""; - htmlcertstrings[22] = ""; - htmlcertstrings[23] = ""; - htmlcertstrings[24] = ""; - htmlcertstrings[25] = "</b>"; - } - - if (pubk) { - SECKEY_DestroyPublicKey(pubk); - } - -#define HTML_OFF 27 - rv = PK11_HashBuf(SEC_OID_MD5, fingerprint, - cert->derCert.data, cert->derCert.len); - - fpitem.data = fingerprint; - fpitem.len = sizeof(fingerprint); - - fpstr = CERT_Hexify (&fpitem,1); - - htmlcertstrings[HTML_OFF] = fpstr; - - commentstring = CERT_GetCertCommentString(cert); - - if (commentstring == NULL) { - htmlcertstrings[HTML_OFF+2] = ""; - htmlcertstrings[HTML_OFF+3] = ""; - htmlcertstrings[HTML_OFF+4] = ""; - } else { - htmlcertstrings[HTML_OFF+2] = - "<b>Comment:</b>" - "<table border=0 cellspacing=0 cellpadding=0><tr>" - "<td width=10> </td><td><font size=3>" - "<textarea name=foobar rows=4 cols=55 onfocus=\"this.blur()\">"; - htmlcertstrings[HTML_OFF+3] = commentstring; - htmlcertstrings[HTML_OFF+4] = "</textarea></font></td></tr></table>"; - } - - ret = gatherStrings(htmlcertstrings); - - if ( issuer ) { - PORT_Free(issuer); - } - - if ( subject ) { - PORT_Free(subject); - } - - if ( version ) { - PORT_Free(version); - } - - if ( serialNumber ) { - PORT_Free(serialNumber); - } - - if ( notBefore ) { - PORT_Free(notBefore); - } - - if ( notAfter ) { - PORT_Free(notAfter); - } - - if ( fpstr ) { - PORT_Free(fpstr); - } - if (DSSPriv) { - PORT_Free(DSSPriv); - } - - if (KMID) { - PORT_Free(KMID); - } - - if ( commentstring ) { - PORT_Free(commentstring); - } - - if ( servername ) { - PORT_Free(servername); - } - - return(ret); -} - diff --git a/security/nss/lib/certhigh/certreq.c b/security/nss/lib/certhigh/certreq.c deleted file mode 100644 index 148b71746..000000000 --- a/security/nss/lib/certhigh/certreq.c +++ /dev/null @@ -1,350 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "cert.h" -#include "certt.h" -#include "secder.h" -#include "key.h" -#include "secitem.h" -#include "secasn1.h" -#include "secerr.h" - -const SEC_ASN1Template CERT_AttributeTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTAttribute) }, - { SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) }, - { SEC_ASN1_SET_OF, offsetof(CERTAttribute, attrValue), - SEC_AnyTemplate }, - { 0 } -}; - -const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = { - { SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate }, -}; - -const SEC_ASN1Template CERT_CertificateRequestTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTCertificateRequest) }, - { SEC_ASN1_INTEGER, - offsetof(CERTCertificateRequest,version) }, - { SEC_ASN1_INLINE, - offsetof(CERTCertificateRequest,subject), - CERT_NameTemplate }, - { SEC_ASN1_INLINE, - offsetof(CERTCertificateRequest,subjectPublicKeyInfo), - CERT_SubjectPublicKeyInfoTemplate }, - { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(CERTCertificateRequest,attributes), - CERT_SetOfAttributeTemplate }, - { 0 } -}; - -SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate) - -CERTCertificate * -CERT_CreateCertificate(unsigned long serialNumber, - CERTName *issuer, - CERTValidity *validity, - CERTCertificateRequest *req) -{ - CERTCertificate *c; - int rv; - PRArenaPool *arena; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - - if ( !arena ) { - return(0); - } - - c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate)); - - if (c) { - c->referenceCount = 1; - c->arena = arena; - - /* - * Default is a plain version 1. - * If extensions are added, it will get changed as appropriate. - */ - rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1); - if (rv) goto loser; - - rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber); - if (rv) goto loser; - - rv = CERT_CopyName(arena, &c->issuer, issuer); - if (rv) goto loser; - - rv = CERT_CopyValidity(arena, &c->validity, validity); - if (rv) goto loser; - - rv = CERT_CopyName(arena, &c->subject, &req->subject); - if (rv) goto loser; - rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo, - &req->subjectPublicKeyInfo); - if (rv) goto loser; - } - return c; - - loser: - CERT_DestroyCertificate(c); - return 0; -} - -/************************************************************************/ -/* It's clear from the comments that the original author of this - * function expected the template for certificate requests to treat - * the attributes as a SET OF ANY. This function expected to be - * passed an array of SECItems each of which contained an already encoded - * Attribute. But the cert request template does not treat the - * Attributes as a SET OF ANY, and AFAIK never has. Instead the template - * encodes attributes as a SET OF xxxxxxx. That is, it expects to encode - * each of the Attributes, not have them pre-encoded. Consequently an - * array of SECItems containing encoded Attributes is of no value to this - * function. But we cannot change the signature of this public function. - * It must continue to take SECItems. - * - * I have recoded this function so that each SECItem contains an - * encoded cert extension. The encoded cert extensions form the list for the - * single attribute of the cert request. In this implementation there is at most - * one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST. - */ - -CERTCertificateRequest * -CERT_CreateCertificateRequest(CERTName *subject, - CERTSubjectPublicKeyInfo *spki, - SECItem **attributes) -{ - CERTCertificateRequest *certreq; - PRArenaPool *arena; - CERTAttribute * attribute; - SECOidData * oidData; - SECStatus rv; - int i = 0; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( arena == NULL ) { - return NULL; - } - - certreq = PORT_ArenaZNew(arena, CERTCertificateRequest); - if (!certreq) { - PORT_FreeArena(arena, PR_FALSE); - return NULL; - } - /* below here it is safe to goto loser */ - - certreq->arena = arena; - - rv = DER_SetUInteger(arena, &certreq->version, - SEC_CERTIFICATE_REQUEST_VERSION); - if (rv != SECSuccess) - goto loser; - - rv = CERT_CopyName(arena, &certreq->subject, subject); - if (rv != SECSuccess) - goto loser; - - rv = SECKEY_CopySubjectPublicKeyInfo(arena, - &certreq->subjectPublicKeyInfo, - spki); - if (rv != SECSuccess) - goto loser; - - certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute*, 2); - if(!certreq->attributes) - goto loser; - - /* Copy over attribute information */ - if (!attributes || !attributes[0]) { - /* - ** Invent empty attribute information. According to the - ** pkcs#10 spec, attributes has this ASN.1 type: - ** - ** attributes [0] IMPLICIT Attributes - ** - ** Which means, we should create a NULL terminated list - ** with the first entry being NULL; - */ - certreq->attributes[0] = NULL; - return certreq; - } - - /* allocate space for attributes */ - attribute = PORT_ArenaZNew(arena, CERTAttribute); - if (!attribute) - goto loser; - - oidData = SECOID_FindOIDByTag( SEC_OID_PKCS9_EXTENSION_REQUEST ); - PORT_Assert(oidData); - if (!oidData) - goto loser; - rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid); - if (rv != SECSuccess) - goto loser; - - for (i = 0; attributes[i] != NULL ; i++) - ; - attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i+1); - if (!attribute->attrValue) - goto loser; - - /* copy attributes */ - for (i = 0; attributes[i]; i++) { - /* - ** Attributes are a SetOf Attribute which implies - ** lexigraphical ordering. It is assumes that the - ** attributes are passed in sorted. If we need to - ** add functionality to sort them, there is an - ** example in the PKCS 7 code. - */ - attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]); - if(!attribute->attrValue[i]) - goto loser; - } - - certreq->attributes[0] = attribute; - - return certreq; - -loser: - CERT_DestroyCertificateRequest(certreq); - return NULL; -} - -void -CERT_DestroyCertificateRequest(CERTCertificateRequest *req) -{ - if (req && req->arena) { - PORT_FreeArena(req->arena, PR_FALSE); - } - return; -} - -static void -setCRExt(void *o, CERTCertExtension **exts) -{ - ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts; -} - -/* -** Set up to start gathering cert extensions for a cert request. -** The list is created as CertExtensions and converted to an -** attribute list by CERT_FinishCRAttributes(). - */ -extern void *cert_StartExtensions(void *owner, PRArenaPool *ownerArena, - void (*setExts)(void *object, CERTCertExtension **exts)); -void * -CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req) -{ - return (cert_StartExtensions ((void *)req, req->arena, setCRExt)); -} - -/* -** At entry req->attributes actually contains an list of cert extensions-- -** req-attributes is overloaded until the list is DER encoded (the first -** ...EncodeItem() below). -** We turn this into an attribute list by encapsulating it -** in a PKCS 10 Attribute structure - */ -SECStatus -CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req) -{ SECItem *extlist; - SECOidData *oidrec; - CERTAttribute *attribute; - - if (!req || !req->arena) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (req->attributes == NULL || req->attributes[0] == NULL) - return SECSuccess; - - extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes, - SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate)); - if (extlist == NULL) - return(SECFailure); - - oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST); - if (oidrec == NULL) - return SECFailure; - - /* now change the list of cert extensions into a list of attributes - */ - req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2); - - attribute = PORT_ArenaZNew(req->arena, CERTAttribute); - - if (req->attributes == NULL || attribute == NULL || - SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2); - - if (attribute->attrValue == NULL) - return SECFailure; - - attribute->attrValue[0] = extlist; - attribute->attrValue[1] = NULL; - req->attributes[0] = attribute; - req->attributes[1] = NULL; - - return SECSuccess; -} - -SECStatus -CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req, - CERTCertExtension ***exts) -{ - if (req == NULL || exts == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (req->attributes == NULL || *req->attributes == NULL) - return SECSuccess; - - if ((*req->attributes)->attrValue == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - return(SEC_ASN1DecodeItem(req->arena, exts, - SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), - (*req->attributes)->attrValue[0])); -} diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c deleted file mode 100644 index b57720d68..000000000 --- a/security/nss/lib/certhigh/certvfy.c +++ /dev/null @@ -1,2075 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#include "nspr.h" -#include "secerr.h" -#include "secport.h" -#include "seccomon.h" -#include "secoid.h" -#include "sslerr.h" -#include "genname.h" -#include "keyhi.h" -#include "cert.h" -#include "certdb.h" -#include "cryptohi.h" - -#ifndef NSS_3_4_CODE -#define NSS_3_4_CODE -#endif /* NSS_3_4_CODE */ -#include "nsspki.h" -#include "pkitm.h" -#include "pkim.h" -#include "pki3hack.h" -#include "base.h" - -#define PENDING_SLOP (24L*60L*60L) - -/* - * WARNING - this function is depricated, and will go away in the near future. - * It has been superseded by CERT_CheckCertValidTimes(). - * - * Check the validity times of a certificate - */ -SECStatus -CERT_CertTimesValid(CERTCertificate *c) -{ - int64 now, notBefore, notAfter, pendingSlop; - SECStatus rv; - - /* if cert is already marked OK, then don't bother to check */ - if ( c->timeOK ) { - return(SECSuccess); - } - - /* get current time */ - now = PR_Now(); - rv = CERT_GetCertTimes(c, ¬Before, ¬After); - - if (rv) { - return(SECFailure); - } - - LL_I2L(pendingSlop, PENDING_SLOP); - LL_SUB(notBefore, notBefore, pendingSlop); - - if (LL_CMP(now, <, notBefore) || LL_CMP(now, >, notAfter)) { - PORT_SetError(SEC_ERROR_EXPIRED_CERTIFICATE); - return(SECFailure); - } - - return(SECSuccess); -} - -/* - * verify the signature of a signed data object with the given DER publickey - */ -SECStatus -CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd, - SECKEYPublicKey *pubKey, - void *wincx) -{ - SECStatus rv; - SECItem sig; - - if ( !pubKey || !sd ) { - PORT_SetError(PR_INVALID_ARGUMENT_ERROR); - return SECFailure; - } - - /* check the signature */ - sig = sd->signature; - /* convert sig->len from bit counts to byte count. */ - DER_ConvertBitString(&sig); - - rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, - &sig, &sd->signatureAlgorithm, NULL, wincx); - - return rv ? SECFailure : SECSuccess; -} - -/* - * verify the signature of a signed data object with the given DER publickey - */ -SECStatus -CERT_VerifySignedDataWithPublicKeyInfo(CERTSignedData *sd, - CERTSubjectPublicKeyInfo *pubKeyInfo, - void *wincx) -{ - SECKEYPublicKey *pubKey; - SECStatus rv = SECFailure; - - /* get cert's public key */ - pubKey = SECKEY_ExtractPublicKey(pubKeyInfo); - if (pubKey) { - rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); - SECKEY_DestroyPublicKey(pubKey); - } - return rv; -} - -/* - * verify the signature of a signed data object with the given certificate - */ -SECStatus -CERT_VerifySignedData(CERTSignedData *sd, CERTCertificate *cert, - int64 t, void *wincx) -{ - SECKEYPublicKey *pubKey = 0; - SECStatus rv = SECFailure; - SECCertTimeValidity validity; - - /* check the certificate's validity */ - validity = CERT_CheckCertValidTimes(cert, t, PR_FALSE); - if ( validity != secCertTimeValid ) { - return rv; - } - - /* get cert's public key */ - pubKey = CERT_ExtractPublicKey(cert); - if (pubKey) { - rv = CERT_VerifySignedDataWithPublicKey(sd, pubKey, wincx); - SECKEY_DestroyPublicKey(pubKey); - } - return rv; -} - - -/* Software FORTEZZA installation hack. The software fortezza installer does - * not have access to the krl and cert.db file. Accept FORTEZZA Certs without - * KRL's in this case. - */ -static int dont_use_krl = 0; -/* not a public exposed function... */ -void sec_SetCheckKRLState(int value) { dont_use_krl = value; } - -SECStatus -SEC_CheckKRL(CERTCertDBHandle *handle,SECKEYPublicKey *key, - CERTCertificate *rootCert, int64 t, void * wincx) -{ - CERTSignedCrl *crl = NULL; - SECStatus rv = SECFailure; - SECStatus rv2; - CERTCrlEntry **crlEntry; - SECCertTimeValidity validity; - CERTCertificate *issuerCert = NULL; - - if (dont_use_krl) return SECSuccess; - - /* first look up the KRL */ - crl = SEC_FindCrlByName(handle,&rootCert->derSubject, SEC_KRL_TYPE); - if (crl == NULL) { - PORT_SetError(SEC_ERROR_NO_KRL); - goto done; - } - - /* get the issuing certificate */ - issuerCert = CERT_FindCertByName(handle, &crl->crl.derName); - if (issuerCert == NULL) { - PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); - goto done; - } - - - /* now verify the KRL signature */ - rv2 = CERT_VerifySignedData(&crl->signatureWrap, issuerCert, t, wincx); - if (rv2 != SECSuccess) { - PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); - goto done; - } - - /* Verify the date validity of the KRL */ - validity = SEC_CheckCrlTimes(&crl->crl, t); - if (validity == secCertTimeExpired) { - PORT_SetError(SEC_ERROR_KRL_EXPIRED); - goto done; - } - - /* now make sure the key in this cert is still valid */ - if (key->keyType != fortezzaKey) { - PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); - goto done; /* This should be an assert? */ - } - - /* now make sure the key is not on the revocation list */ - for (crlEntry = crl->crl.entries; crlEntry && *crlEntry; crlEntry++) { - if (PORT_Memcmp((*crlEntry)->serialNumber.data, - key->u.fortezza.KMID, - (*crlEntry)->serialNumber.len) == 0) { - PORT_SetError(SEC_ERROR_REVOKED_KEY); - goto done; - } - } - rv = SECSuccess; - -done: - if (issuerCert) CERT_DestroyCertificate(issuerCert); - if (crl) SEC_DestroyCrl(crl); - return rv; -} - -SECStatus -SEC_CheckCRL(CERTCertDBHandle *handle,CERTCertificate *cert, - CERTCertificate *caCert, int64 t, void * wincx) -{ - return CERT_CheckCRL(cert, caCert, NULL, t, wincx); -} - -/* - * Find the issuer of a cert. Use the authorityKeyID if it exists. - */ -CERTCertificate * -CERT_FindCertIssuer(CERTCertificate *cert, int64 validTime, SECCertUsage usage) -{ -#ifdef NSS_CLASSIC - CERTAuthKeyID * authorityKeyID = NULL; - CERTCertificate * issuerCert = NULL; - SECItem * caName; - PRArenaPool *tmpArena = NULL; - - tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - - if ( !tmpArena ) { - goto loser; - } - authorityKeyID = CERT_FindAuthKeyIDExten(tmpArena,cert); - - if ( authorityKeyID != NULL ) { - /* has the authority key ID extension */ - if ( authorityKeyID->keyID.data != NULL ) { - /* extension contains a key ID, so lookup based on it */ - issuerCert = CERT_FindCertByKeyID(cert->dbhandle, &cert->derIssuer, - &authorityKeyID->keyID); - if ( issuerCert == NULL ) { - PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); - goto loser; - } - - } else if ( authorityKeyID->authCertIssuer != NULL ) { - /* no key ID, so try issuer and serial number */ - caName = (SECItem*)CERT_GetGeneralNameByType(authorityKeyID->authCertIssuer, - certDirectoryName, PR_TRUE); - - /* - * caName is NULL when the authCertIssuer field is not - * being used, or other name form is used instead. - * If the directoryName format and serialNumber fields are - * used, we use them to find the CA cert. - * Note: - * By the time it gets here, we known for sure that if the - * authCertIssuer exists, then the authCertSerialNumber - * must also exists (CERT_DecodeAuthKeyID() ensures this). - * We don't need to check again. - */ - - if (caName != NULL) { - CERTIssuerAndSN issuerSN; - - issuerSN.derIssuer.data = caName->data; - issuerSN.derIssuer.len = caName->len; - issuerSN.serialNumber.data = - authorityKeyID->authCertSerialNumber.data; - issuerSN.serialNumber.len = - authorityKeyID->authCertSerialNumber.len; - issuerCert = CERT_FindCertByIssuerAndSN(cert->dbhandle, - &issuerSN); - if ( issuerCert == NULL ) { - PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); - goto loser; - } - } - } - } - if ( issuerCert == NULL ) { - /* if there is not authorityKeyID, then try to find the issuer */ - /* find a valid CA cert with correct usage */ - issuerCert = CERT_FindMatchingCert(cert->dbhandle, - &cert->derIssuer, - certOwnerCA, usage, PR_TRUE, - validTime, PR_TRUE); - - /* if that fails, then fall back to grabbing any cert with right name*/ - if ( issuerCert == NULL ) { - issuerCert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer); - if ( issuerCert == NULL ) { - PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); - } - } - } - -loser: - if (tmpArena != NULL) { - PORT_FreeArena(tmpArena, PR_FALSE); - tmpArena = NULL; - } - - return(issuerCert); -#else - NSSCertificate *me; - NSSTime *nssTime; - NSSTrustDomain *td; - NSSCryptoContext *cc; - NSSCertificate *chain[3]; - NSSUsage nssUsage; - PRStatus status; - - me = STAN_GetNSSCertificate(cert); - if (!me) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - nssTime = NSSTime_SetPRTime(NULL, validTime); - nssUsage.anyUsage = PR_FALSE; - nssUsage.nss3usage = usage; - nssUsage.nss3lookingForCA = PR_TRUE; - memset(chain, 0, 3*sizeof(NSSCertificate *)); - td = STAN_GetDefaultTrustDomain(); - cc = STAN_GetDefaultCryptoContext(); - (void)NSSCertificate_BuildChain(me, nssTime, &nssUsage, NULL, - chain, 2, NULL, &status, td, cc); - nss_ZFreeIf(nssTime); - if (status == PR_SUCCESS) { - PORT_Assert(me == chain[0]); - /* if it's a root, the chain will only have one cert */ - if (!chain[1]) { - /* already has a reference from the call to BuildChain */ - return cert; - } - NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ - return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ - } - if (chain[0]) { - PORT_Assert(me == chain[0]); - NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ - } - PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); - return NULL; -#endif -} - -/* - * return required trust flags for various cert usages for CAs - */ -SECStatus -CERT_TrustFlagsForCACertUsage(SECCertUsage usage, - unsigned int *retFlags, - SECTrustType *retTrustType) -{ - unsigned int requiredFlags; - SECTrustType trustType; - - switch ( usage ) { - case certUsageSSLClient: - requiredFlags = CERTDB_TRUSTED_CLIENT_CA; - trustType = trustSSL; - break; - case certUsageSSLServer: - case certUsageSSLCA: - requiredFlags = CERTDB_TRUSTED_CA; - trustType = trustSSL; - break; - case certUsageSSLServerWithStepUp: - requiredFlags = CERTDB_TRUSTED_CA | CERTDB_GOVT_APPROVED_CA; - trustType = trustSSL; - break; - case certUsageEmailSigner: - case certUsageEmailRecipient: - requiredFlags = CERTDB_TRUSTED_CA; - trustType = trustEmail; - break; - case certUsageObjectSigner: - requiredFlags = CERTDB_TRUSTED_CA; - trustType = trustObjectSigning; - break; - case certUsageVerifyCA: - case certUsageAnyCA: - case certUsageStatusResponder: - requiredFlags = CERTDB_TRUSTED_CA; - trustType = trustTypeNone; - break; - default: - PORT_Assert(0); - goto loser; - } - if ( retFlags != NULL ) { - *retFlags = requiredFlags; - } - if ( retTrustType != NULL ) { - *retTrustType = trustType; - } - - return(SECSuccess); -loser: - return(SECFailure); -} - - - - - -static void -AddToVerifyLog(CERTVerifyLog *log, CERTCertificate *cert, unsigned long error, - unsigned int depth, void *arg) -{ - CERTVerifyLogNode *node, *tnode; - - PORT_Assert(log != NULL); - - node = (CERTVerifyLogNode *)PORT_ArenaAlloc(log->arena, - sizeof(CERTVerifyLogNode)); - if ( node != NULL ) { - node->cert = CERT_DupCertificate(cert); - node->error = error; - node->depth = depth; - node->arg = arg; - - if ( log->tail == NULL ) { - /* empty list */ - log->head = log->tail = node; - node->prev = NULL; - node->next = NULL; - } else if ( depth >= log->tail->depth ) { - /* add to tail */ - node->prev = log->tail; - log->tail->next = node; - log->tail = node; - node->next = NULL; - } else if ( depth < log->head->depth ) { - /* add at head */ - node->prev = NULL; - node->next = log->head; - log->head->prev = node; - log->head = node; - } else { - /* add in middle */ - tnode = log->tail; - while ( tnode != NULL ) { - if ( depth >= tnode->depth ) { - /* insert after tnode */ - node->prev = tnode; - node->next = tnode->next; - tnode->next->prev = node; - tnode->next = node; - break; - } - - tnode = tnode->prev; - } - } - - log->count++; - } - return; -} - -#define EXIT_IF_NOT_LOGGING(log) \ - if ( log == NULL ) { \ - goto loser; \ - } - -#define LOG_ERROR_OR_EXIT(log,cert,depth,arg) \ - if ( log != NULL ) { \ - AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \ - } else { \ - goto loser; \ - } - -#define LOG_ERROR(log,cert,depth,arg) \ - if ( log != NULL ) { \ - AddToVerifyLog(log, cert, PORT_GetError(), depth, (void *)arg); \ - } - - -typedef enum { cbd_None, cbd_User, cbd_CA } cbd_FortezzaType; - -static SECStatus -cert_VerifyFortezzaV1Cert(CERTCertDBHandle *handle, CERTCertificate *cert, - cbd_FortezzaType *next_type, cbd_FortezzaType last_type, - int64 t, void *wincx) -{ - unsigned char priv = 0; - SECKEYPublicKey *key; - SECStatus rv; - - *next_type = cbd_CA; - - /* read the key */ - key = CERT_ExtractPublicKey(cert); - - /* Cant' get Key? fail. */ - if (key == NULL) { - PORT_SetError(SEC_ERROR_BAD_KEY); - return SECFailure; - } - - - /* if the issuer is not an old fortezza cert, we bail */ - if (key->keyType != fortezzaKey) { - SECKEY_DestroyPublicKey(key); - /* CA Cert not fortezza */ - PORT_SetError(SEC_ERROR_NOT_FORTEZZA_ISSUER); - return SECFailure; - } - - /* get the privilege mask */ - if (key->u.fortezza.DSSpriviledge.len > 0) { - priv = key->u.fortezza.DSSpriviledge.data[0]; - } - - /* - * make sure the CA's keys are OK - */ - - rv = SEC_CheckKRL(handle, key, NULL, t, wincx); - SECKEY_DestroyPublicKey(key); - if (rv != SECSuccess) { - return rv; - } - - switch (last_type) { - case cbd_User: - /* first check for subordination */ - /*rv = FortezzaSubordinateCheck(cert,issuerCert);*/ - rv = SECSuccess; - - /* now check for issuer privilege */ - if ((rv != SECSuccess) || ((priv & 0x10) == 0)) { - /* bail */ - PORT_SetError (SEC_ERROR_CA_CERT_INVALID); - return SECFailure; - } - break; - case cbd_CA: - if ((priv & 0x20) == 0) { - /* bail */ - PORT_SetError (SEC_ERROR_CA_CERT_INVALID); - return SECFailure; - } - break; - case cbd_None: - *next_type = (priv & 0x30) ? cbd_CA : cbd_User; - break; - default: - /* bail */ /* shouldn't ever happen */ - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - return SECFailure; - } - return SECSuccess; -} - - -static SECStatus -cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, PRBool* sigerror, - SECCertUsage certUsage, int64 t, void *wincx, - CERTVerifyLog *log, PRBool* revoked) -{ - SECTrustType trustType; - CERTBasicConstraints basicConstraint; - CERTCertificate *issuerCert = NULL; - CERTCertificate *subjectCert = NULL; - CERTCertificate *badCert = NULL; - PRBool isca; - PRBool isFortezzaV1 = PR_FALSE; - SECStatus rv; - SECStatus rvFinal = SECSuccess; - int count; - int currentPathLen = 0; - int pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; - int flags; - unsigned int caCertType; - unsigned int requiredCAKeyUsage; - unsigned int requiredFlags; - PRArenaPool *arena = NULL; - CERTGeneralName *namesList = NULL; - CERTCertificate **certsList = NULL; - int certsListLen = 16; - int namesCount = 0; - PRBool subjectCertIsSelfIssued; - - cbd_FortezzaType last_type = cbd_None; - - if (revoked) { - *revoked = PR_FALSE; - } - - if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, - &requiredCAKeyUsage, - &caCertType) - != SECSuccess ) { - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredCAKeyUsage = 0; - caCertType = 0; - } - - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - case certUsageSSLCA: - case certUsageSSLServerWithStepUp: - case certUsageEmailSigner: - case certUsageEmailRecipient: - case certUsageObjectSigner: - case certUsageVerifyCA: - case certUsageStatusResponder: - if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, - &trustType) != SECSuccess ) { - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredFlags = 0; - trustType = trustSSL; - } - break; - default: - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredFlags = 0; - trustType = trustSSL;/* This used to be 0, but we need something - * that matches the enumeration type. - */ - caCertType = 0; - } - - subjectCert = CERT_DupCertificate(cert); - if ( subjectCert == NULL ) { - goto loser; - } - - /* determine if the cert is fortezza. - */ - isFortezzaV1 = (PRBool) - (CERT_GetCertKeyType(&subjectCert->subjectPublicKeyInfo) - == fortezzaKey); - - if (isFortezzaV1) { - rv = cert_VerifyFortezzaV1Cert(handle, subjectCert, &last_type, - cbd_None, t, wincx); - if (rv == SECFailure) { - /**** PORT_SetError is already set by cert_VerifyFortezzaV1Cert **/ - LOG_ERROR_OR_EXIT(log,subjectCert,0,0); - } - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto loser; - } - - certsList = PORT_ZNewArray(CERTCertificate *, certsListLen); - if (certsList == NULL) - goto loser; - - /* RFC 3280 says that the name constraints will apply to the names - ** in the leaf (EE) cert, whether it is self issued or not, so - ** we pretend that it is not. - */ - subjectCertIsSelfIssued = PR_FALSE; - for ( count = 0; count < CERT_MAX_CERT_CHAIN; count++ ) { - PRBool validCAOverride = PR_FALSE; - - /* Construct a list of names for the current and all previous - * certifcates (except leaf (EE) certs, root CAs, and self-issued - * intermediate CAs) to be verified against the name constraints - * extension of the issuer certificate. - */ - if (subjectCertIsSelfIssued == PR_FALSE) { - CERTGeneralName *subjectNameList; - int subjectNameListLen; - int i; - subjectNameList = CERT_GetCertificateNames(subjectCert, arena); - subjectNameListLen = CERT_GetNamesLength(subjectNameList); - if (certsListLen <= namesCount + subjectNameListLen) { - CERTCertificate **tmpCertsList; - certsListLen = (namesCount + subjectNameListLen) * 2; - tmpCertsList = - (CERTCertificate **)PORT_Realloc(certsList, - certsListLen * sizeof(CERTCertificate *)); - if (tmpCertsList == NULL) { - goto loser; - } - certsList = tmpCertsList; - } - for (i = 0; i < subjectNameListLen; i++) { - certsList[namesCount + i] = subjectCert; - } - namesCount += subjectNameListLen; - namesList = cert_CombineNamesLists(namesList, subjectNameList); - } - - /* check if the cert has an unsupported critical extension */ - if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) { - PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); - LOG_ERROR_OR_EXIT(log,subjectCert,count,0); - } - - /* find the certificate of the issuer */ - issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); - if ( ! issuerCert ) { - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - LOG_ERROR(log,subjectCert,count,0); - goto loser; - } - - /* verify the signature on the cert */ - if ( checkSig ) { - rv = CERT_VerifySignedData(&subjectCert->signatureWrap, - issuerCert, t, wincx); - - if ( rv != SECSuccess ) { - if (sigerror) { - *sigerror = PR_TRUE; - } - if ( PORT_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE ) { - PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE); - LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); - } else { - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - LOG_ERROR_OR_EXIT(log,subjectCert,count,0); - } - } - } - - /* - * XXX - fortezza may need error logging stuff added - */ - if (isFortezzaV1) { - rv = cert_VerifyFortezzaV1Cert(handle, issuerCert, &last_type, - last_type, t, wincx); - if (rv == SECFailure) { - /**** PORT_SetError is already set by * - * cert_VerifyFortezzaV1Cert **/ - LOG_ERROR_OR_EXIT(log,subjectCert,0,0); - } - } - - /* If the basicConstraint extension is included in an immediate CA - * certificate, make sure that the isCA flag is on. If the - * pathLenConstraint component exists, it must be greater than the - * number of CA certificates we have seen so far. If the extension - * is omitted, we will assume that this is a CA certificate with - * an unlimited pathLenConstraint (since it already passes the - * netscape-cert-type extension checking). - * - * In the fortezza (V1) case, we've already checked the CA bits - * in the key, so we're presumed to be a CA; however we really don't - * want to bypass Basic constraint or netscape extension parsing. - * - * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA - */ - - rv = CERT_FindBasicConstraintExten(issuerCert, &basicConstraint); - if ( rv != SECSuccess ) { - if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { - LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); - } - pathLengthLimit = CERT_UNLIMITED_PATH_CONSTRAINT; - /* no basic constraints found, if we're fortezza, CA bit is already - * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca - * isca = PR_FALSE */ - isca = isFortezzaV1; - } else { - if ( basicConstraint.isCA == PR_FALSE ) { - PORT_SetError (SEC_ERROR_CA_CERT_INVALID); - LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); - } - pathLengthLimit = basicConstraint.pathLenConstraint; - isca = PR_TRUE; - } - /* make sure that the path len constraint is properly set.*/ - if (pathLengthLimit >= 0 && currentPathLen > pathLengthLimit) { - PORT_SetError (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); - LOG_ERROR_OR_EXIT(log, issuerCert, count+1, pathLengthLimit); - } - - /* XXX - the error logging may need to go down into CRL stuff at some - * point - */ - /* check revoked list (issuer) */ - rv = SEC_CheckCRL(handle, subjectCert, issuerCert, t, wincx); - if (rv == SECFailure) { - if (revoked) { - *revoked = PR_TRUE; - } - LOG_ERROR_OR_EXIT(log,subjectCert,count,0); - } else if (rv == SECWouldBlock) { - /* We found something fishy, so we intend to issue an - * error to the user, but the user may wish to continue - * processing, in which case we better make sure nothing - * worse has happened... so keep cranking the loop */ - rvFinal = SECFailure; - if (revoked) { - *revoked = PR_TRUE; - } - LOG_ERROR(log,subjectCert,count,0); - } - - if ( issuerCert->trust ) { - /* we have some trust info, but this does NOT imply that this - * cert is actually trusted for any purpose. The cert may be - * explicitly UNtrusted. We won't know until we examine the - * trust bits. - */ - if (certUsage == certUsageStatusResponder) { - /* XXX NSS has done this for years, but it seems incorrect. */ - rv = rvFinal; - goto done; - } - - /* - * check the trust parms of the issuer - */ - if ( certUsage == certUsageVerifyCA ) { - if ( subjectCert->nsCertType & NS_CERT_TYPE_EMAIL_CA ) { - trustType = trustEmail; - } else if ( subjectCert->nsCertType & NS_CERT_TYPE_SSL_CA ) { - trustType = trustSSL; - } else { - trustType = trustObjectSigning; - } - } - - flags = SEC_GET_TRUST_FLAGS(issuerCert->trust, trustType); - - if (flags & CERTDB_VALID_CA) { - if ( ( flags & requiredFlags ) == requiredFlags) { - /* we found a trusted one, so return */ - rv = rvFinal; - goto done; - } - validCAOverride = PR_TRUE; - } - } - - if (!validCAOverride) { - /* - * Make sure that if this is an intermediate CA in the chain that - * it was given permission by its signer to be a CA. - */ - /* - * if basicConstraints says it is a ca, then we check the - * nsCertType. If the nsCertType has any CA bits set, then - * it must have the right one. - */ - if (!isca || (issuerCert->nsCertType & NS_CERT_TYPE_CA)) { - isca = (issuerCert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; - } - - if ( !isca ) { - PORT_SetError(SEC_ERROR_CA_CERT_INVALID); - LOG_ERROR_OR_EXIT(log,issuerCert,count+1,0); - } - - /* make sure key usage allows cert signing */ - if (CERT_CheckKeyUsage(issuerCert, requiredCAKeyUsage) != SECSuccess) { - PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); - LOG_ERROR_OR_EXIT(log,issuerCert,count+1,requiredCAKeyUsage); - } - } - - /* make sure that the entire chain is within the name space of the - ** current issuer certificate. - */ - rv = CERT_CompareNameSpace(issuerCert, namesList, certsList, - arena, &badCert); - if (rv != SECSuccess || badCert != NULL) { - PORT_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE); - LOG_ERROR_OR_EXIT(log, badCert, count + 1, 0); - goto loser; - } - /* make sure that the issuer is not self signed. If it is, then - * stop here to prevent looping. - */ - if (issuerCert->isRoot) { - PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); - LOG_ERROR(log, issuerCert, count+1, 0); - goto loser; - } - /* The issuer cert will be the subject cert in the next loop. - * A cert is self-issued if its subject and issuer are equal and - * both are of non-zero length. - */ - subjectCertIsSelfIssued = (PRBool) - SECITEM_ItemsAreEqual(&issuerCert->derIssuer, - &issuerCert->derSubject) && - issuerCert->derSubject.len > 0; - if (subjectCertIsSelfIssued == PR_FALSE) { - /* RFC 3280 says only non-self-issued intermediate CA certs - * count in path length. - */ - ++currentPathLen; - } - - CERT_DestroyCertificate(subjectCert); - subjectCert = issuerCert; - issuerCert = NULL; - } - - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - LOG_ERROR(log,subjectCert,count,0); -loser: - rv = SECFailure; -done: - if (certsList != NULL) { - PORT_Free(certsList); - } - if ( issuerCert ) { - CERT_DestroyCertificate(issuerCert); - } - - if ( subjectCert ) { - CERT_DestroyCertificate(subjectCert); - } - - if ( arena != NULL ) { - PORT_FreeArena(arena, PR_FALSE); - } - return rv; -} - -SECStatus -CERT_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertUsage certUsage, int64 t, - void *wincx, CERTVerifyLog *log) -{ - return cert_VerifyCertChain(handle, cert, checkSig, NULL, certUsage, t, - wincx, log, NULL); -} - -/* - * verify that a CA can sign a certificate with the requested usage. - * XXX This function completely ignores cert path length constraints! - */ -SECStatus -CERT_VerifyCACertForUsage(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertUsage certUsage, int64 t, - void *wincx, CERTVerifyLog *log) -{ - SECTrustType trustType; - CERTBasicConstraints basicConstraint; - PRBool isca; - PRBool validCAOverride = PR_FALSE; - SECStatus rv; - SECComparison rvCompare; - SECStatus rvFinal = SECSuccess; - int flags; - unsigned int caCertType; - unsigned int requiredCAKeyUsage; - unsigned int requiredFlags; - CERTCertificate *issuerCert; - - - if (CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_TRUE, - &requiredCAKeyUsage, - &caCertType) != SECSuccess ) { - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredCAKeyUsage = 0; - caCertType = 0; - } - - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - case certUsageSSLCA: - case certUsageSSLServerWithStepUp: - case certUsageEmailSigner: - case certUsageEmailRecipient: - case certUsageObjectSigner: - case certUsageVerifyCA: - case certUsageStatusResponder: - if ( CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, - &trustType) != SECSuccess ) { - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredFlags = 0; - trustType = trustSSL; - } - break; - default: - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredFlags = 0; - trustType = trustSSL;/* This used to be 0, but we need something - * that matches the enumeration type. - */ - caCertType = 0; - } - - /* If the basicConstraint extension is included in an intermmediate CA - * certificate, make sure that the isCA flag is on. If the - * pathLenConstraint component exists, it must be greater than the - * number of CA certificates we have seen so far. If the extension - * is omitted, we will assume that this is a CA certificate with - * an unlimited pathLenConstraint (since it already passes the - * netscape-cert-type extension checking). - * - * In the fortezza (V1) case, we've already checked the CA bits - * in the key, so we're presumed to be a CA; however we really don't - * want to bypass Basic constraint or netscape extension parsing. - * - * In Fortezza V2, basicConstraint will be set for every CA,PCA,PAA - */ - - rv = CERT_FindBasicConstraintExten(cert, &basicConstraint); - if ( rv != SECSuccess ) { - if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) { - LOG_ERROR_OR_EXIT(log,cert,0,0); - } - /* no basic constraints found, if we're fortezza, CA bit is already - * verified (isca = PR_TRUE). otherwise, we aren't (yet) a ca - * isca = PR_FALSE */ - isca = PR_FALSE; - } else { - if ( basicConstraint.isCA == PR_FALSE ) { - PORT_SetError (SEC_ERROR_CA_CERT_INVALID); - LOG_ERROR_OR_EXIT(log,cert,0,0); - } - - /* can't check path length if we don't know the previous path */ - isca = PR_TRUE; - } - - if ( cert->trust ) { - /* we have some trust info, but this does NOT imply that this - * cert is actually trusted for any purpose. The cert may be - * explicitly UNtrusted. We won't know until we examine the - * trust bits. - */ - if (certUsage == certUsageStatusResponder) { - /* Check the special case of certUsageStatusResponder */ - issuerCert = CERT_FindCertIssuer(cert, t, certUsage); - if (issuerCert) { - if (SEC_CheckCRL(handle, cert, issuerCert, t, wincx) - != SECSuccess) { - PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); - CERT_DestroyCertificate(issuerCert); - goto loser; - } - CERT_DestroyCertificate(issuerCert); - } - /* XXX We have NOT determined that this cert is trusted. - * For years, NSS has treated this as trusted, - * but it seems incorrect. - */ - rv = rvFinal; - goto done; - } - - /* - * check the trust parms of the issuer - */ - flags = SEC_GET_TRUST_FLAGS(cert->trust, trustType); - - if (flags & CERTDB_VALID_CA) { - if ( ( flags & requiredFlags ) == requiredFlags) { - /* we found a trusted one, so return */ - rv = rvFinal; - goto done; - } - validCAOverride = PR_TRUE; - } - } - if (!validCAOverride) { - /* - * Make sure that if this is an intermediate CA in the chain that - * it was given permission by its signer to be a CA. - */ - /* - * if basicConstraints says it is a ca, then we check the - * nsCertType. If the nsCertType has any CA bits set, then - * it must have the right one. - */ - if (!isca || (cert->nsCertType & NS_CERT_TYPE_CA)) { - isca = (cert->nsCertType & caCertType) ? PR_TRUE : PR_FALSE; - } - - if (!isca) { - PORT_SetError(SEC_ERROR_CA_CERT_INVALID); - LOG_ERROR_OR_EXIT(log,cert,0,0); - } - - /* make sure key usage allows cert signing */ - if (CERT_CheckKeyUsage(cert, requiredCAKeyUsage) != SECSuccess) { - PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); - LOG_ERROR_OR_EXIT(log,cert,0,requiredCAKeyUsage); - } - } - /* make sure that the issuer is not self signed. If it is, then - * stop here to prevent looping. - */ - rvCompare = SECITEM_CompareItem(&cert->derSubject, &cert->derIssuer); - if (rvCompare == SECEqual) { - PORT_SetError(SEC_ERROR_UNTRUSTED_ISSUER); - LOG_ERROR(log, cert, 0, 0); - goto loser; - } - - return CERT_VerifyCertChain(handle, cert, checkSig, certUsage, t, - wincx, log); -loser: - rv = SECFailure; -done: - return rv; -} - -#define NEXT_USAGE() { \ - i*=2; \ - certUsage++; \ - continue; \ -} - -#define VALID_USAGE() { \ - NEXT_USAGE(); \ -} - -#define INVALID_USAGE() { \ - if (returnedUsages) { \ - *returnedUsages &= (~i); \ - } \ - if (PR_TRUE == requiredUsage) { \ - valid = SECFailure; \ - } \ - NEXT_USAGE(); \ -} - -/* - * verify a certificate by checking if it's valid and that we - * trust the issuer. - * - * certificateUsage contains a bitfield of all cert usages that are - * required for verification to succeed - * - * a bitfield of cert usages is returned in *returnedUsages - * if requiredUsages is non-zero, the returned bitmap is only - * for those required usages, otherwise it is for all usages - * - */ -SECStatus -CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertificateUsage requiredUsages, int64 t, - void *wincx, CERTVerifyLog *log, SECCertificateUsage* returnedUsages) -{ - SECStatus rv; - SECStatus valid; - unsigned int requiredKeyUsage; - unsigned int requiredCertType; - unsigned int flags; - unsigned int certType; - PRBool allowOverride; - SECCertTimeValidity validity; - CERTStatusConfig *statusConfig; - PRInt32 i; - SECCertUsage certUsage = 0; - PRBool checkedOCSP = PR_FALSE; - PRBool checkAllUsages = PR_FALSE; - PRBool revoked = PR_FALSE; - PRBool sigerror = PR_FALSE; - - if (!requiredUsages) { - /* there are no required usages, so the user probably wants to - get status for all usages */ - checkAllUsages = PR_TRUE; - } - - if (returnedUsages) { - *returnedUsages = 0; - } else { - /* we don't have a place to return status for all usages, - so we can skip checks for usages that aren't required */ - checkAllUsages = PR_FALSE; - } - valid = SECSuccess ; /* start off assuming cert is valid */ - - /* make sure that the cert is valid at time t */ - allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) || - (requiredUsages & certificateUsageSSLServerWithStepUp)); - validity = CERT_CheckCertValidTimes(cert, t, allowOverride); - if ( validity != secCertTimeValid ) { - valid = SECFailure; - LOG_ERROR_OR_EXIT(log,cert,0,validity); - } - - /* check key usage and netscape cert type */ - cert_GetCertType(cert); - certType = cert->nsCertType; - - for (i=1; i<=certificateUsageHighest && - (SECSuccess == valid || returnedUsages || log) ; ) { - PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE; - if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) { - NEXT_USAGE(); - } - if (returnedUsages) { - *returnedUsages |= i; /* start off assuming this usage is valid */ - } - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - case certUsageSSLServerWithStepUp: - case certUsageSSLCA: - case certUsageEmailSigner: - case certUsageEmailRecipient: - case certUsageObjectSigner: - case certUsageStatusResponder: - rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, - &requiredKeyUsage, - &requiredCertType); - if ( rv != SECSuccess ) { - PORT_Assert(0); - /* EXIT_IF_NOT_LOGGING(log); XXX ??? */ - requiredKeyUsage = 0; - requiredCertType = 0; - INVALID_USAGE(); - } - break; - - case certUsageAnyCA: - case certUsageProtectedObjectSigner: - case certUsageUserCertImport: - case certUsageVerifyCA: - /* these usages cannot be verified */ - NEXT_USAGE(); - - default: - PORT_Assert(0); - requiredKeyUsage = 0; - requiredCertType = 0; - INVALID_USAGE(); - } - if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { - if (PR_TRUE == requiredUsage) { - PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); - } - LOG_ERROR(log,cert,0,requiredKeyUsage); - INVALID_USAGE(); - } - if ( !( certType & requiredCertType ) ) { - if (PR_TRUE == requiredUsage) { - PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); - } - LOG_ERROR(log,cert,0,requiredCertType); - INVALID_USAGE(); - } - - /* check trust flags to see if this cert is directly trusted */ - if ( cert->trust ) { /* the cert is in the DB */ - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - flags = cert->trust->sslFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/ - if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ - VALID_USAGE(); - } else { /* don't trust this cert */ - if (PR_TRUE == requiredUsage) { - PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); - } - LOG_ERROR(log,cert,0,flags); - INVALID_USAGE(); - } - } - break; - case certUsageSSLServerWithStepUp: - /* XXX - step up certs can't be directly trusted */ - break; - case certUsageSSLCA: - break; - case certUsageEmailSigner: - case certUsageEmailRecipient: - flags = cert->trust->emailFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) == - ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) { - VALID_USAGE(); - } - break; - case certUsageObjectSigner: - flags = cert->trust->objectSigningFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/ - if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ - VALID_USAGE(); - } else { /* don't trust this cert */ - if (PR_TRUE == requiredUsage) { - PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); - } - LOG_ERROR(log,cert,0,flags); - INVALID_USAGE(); - } - } - break; - case certUsageVerifyCA: - case certUsageStatusResponder: - flags = cert->trust->sslFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - VALID_USAGE(); - } - flags = cert->trust->emailFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - VALID_USAGE(); - } - flags = cert->trust->objectSigningFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - VALID_USAGE(); - } - break; - case certUsageAnyCA: - case certUsageProtectedObjectSigner: - case certUsageUserCertImport: - /* XXX to make the compiler happy. Should these be - * explicitly handled? - */ - break; - } - } - - if (PR_TRUE == revoked || PR_TRUE == sigerror) { - INVALID_USAGE(); - } - - rv = cert_VerifyCertChain(handle, cert, - checkSig, &sigerror, - certUsage, t, wincx, log, - &revoked); - - if (rv != SECSuccess) { - /* EXIT_IF_NOT_LOGGING(log); XXX ???? */ - INVALID_USAGE(); - } - - /* - * Check OCSP revocation status, but only if the cert we are checking - * is not a status reponder itself. We only do this in the case - * where we checked the cert chain (above); explicit trust "wins" - * (avoids status checking, just as it avoids CRL checking) by - * bypassing this code. - */ - - if (PR_FALSE == checkedOCSP) { - checkedOCSP = PR_TRUE; /* only check OCSP once */ - statusConfig = CERT_GetStatusConfig(handle); - if ( (! (requiredUsages == certificateUsageStatusResponder)) && - statusConfig != NULL) { - if (statusConfig->statusChecker != NULL) { - rv = (* statusConfig->statusChecker)(handle, cert, - t, wincx); - if (rv != SECSuccess) { - LOG_ERROR(log,cert,0,0); - revoked = PR_TRUE; - INVALID_USAGE(); - } - } - } - } - - NEXT_USAGE(); - } - -loser: - return(valid); -} - -/* obsolete, do not use for new code */ -SECStatus -CERT_VerifyCert(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertUsage certUsage, int64 t, - void *wincx, CERTVerifyLog *log) -{ - SECStatus rv; - unsigned int requiredKeyUsage; - unsigned int requiredCertType; - unsigned int flags; - unsigned int certType; - PRBool allowOverride; - SECCertTimeValidity validity; - CERTStatusConfig *statusConfig; - -#ifdef notdef - /* check if this cert is in the Evil list */ - rv = CERT_CheckForEvilCert(cert); - if ( rv != SECSuccess ) { - PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); - LOG_ERROR_OR_EXIT(log,cert,0,0); - } -#endif - - /* make sure that the cert is valid at time t */ - allowOverride = (PRBool)((certUsage == certUsageSSLServer) || - (certUsage == certUsageSSLServerWithStepUp)); - validity = CERT_CheckCertValidTimes(cert, t, allowOverride); - if ( validity != secCertTimeValid ) { - LOG_ERROR_OR_EXIT(log,cert,0,validity); - } - - /* check key usage and netscape cert type */ - cert_GetCertType(cert); - certType = cert->nsCertType; - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - case certUsageSSLServerWithStepUp: - case certUsageSSLCA: - case certUsageEmailSigner: - case certUsageEmailRecipient: - case certUsageObjectSigner: - case certUsageStatusResponder: - rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, PR_FALSE, - &requiredKeyUsage, - &requiredCertType); - if ( rv != SECSuccess ) { - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredKeyUsage = 0; - requiredCertType = 0; - } - break; - case certUsageVerifyCA: - requiredKeyUsage = KU_KEY_CERT_SIGN; - requiredCertType = NS_CERT_TYPE_CA; - if ( ! ( certType & NS_CERT_TYPE_CA ) ) { - certType |= NS_CERT_TYPE_CA; - } - break; - default: - PORT_Assert(0); - EXIT_IF_NOT_LOGGING(log); - requiredKeyUsage = 0; - requiredCertType = 0; - } - if ( CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess ) { - PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE); - LOG_ERROR_OR_EXIT(log,cert,0,requiredKeyUsage); - } - if ( !( certType & requiredCertType ) ) { - PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE); - LOG_ERROR_OR_EXIT(log,cert,0,requiredCertType); - } - - /* check trust flags to see if this cert is directly trusted */ - if ( cert->trust ) { /* the cert is in the DB */ - switch ( certUsage ) { - case certUsageSSLClient: - case certUsageSSLServer: - flags = cert->trust->sslFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/ - if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ - goto winner; - } else { /* don't trust this cert */ - PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); - LOG_ERROR_OR_EXIT(log,cert,0,flags); - } - } - break; - case certUsageSSLServerWithStepUp: - /* XXX - step up certs can't be directly trusted */ - break; - case certUsageSSLCA: - break; - case certUsageEmailSigner: - case certUsageEmailRecipient: - flags = cert->trust->emailFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) == - ( CERTDB_VALID_PEER | CERTDB_TRUSTED ) ) { - goto winner; - } - break; - case certUsageObjectSigner: - flags = cert->trust->objectSigningFlags; - - /* is the cert directly trusted or not trusted ? */ - if ( flags & CERTDB_VALID_PEER ) {/*the trust record is valid*/ - if ( flags & CERTDB_TRUSTED ) { /* trust this cert */ - goto winner; - } else { /* don't trust this cert */ - PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); - LOG_ERROR_OR_EXIT(log,cert,0,flags); - } - } - break; - case certUsageVerifyCA: - case certUsageStatusResponder: - flags = cert->trust->sslFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - goto winner; - } - flags = cert->trust->emailFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - goto winner; - } - flags = cert->trust->objectSigningFlags; - /* is the cert directly trusted or not trusted ? */ - if ( ( flags & ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) == - ( CERTDB_VALID_CA | CERTDB_TRUSTED_CA ) ) { - goto winner; - } - break; - case certUsageAnyCA: - case certUsageProtectedObjectSigner: - case certUsageUserCertImport: - /* XXX to make the compiler happy. Should these be - * explicitly handled? - */ - break; - } - } - - rv = CERT_VerifyCertChain(handle, cert, checkSig, certUsage, - t, wincx, log); - if (rv != SECSuccess) { - EXIT_IF_NOT_LOGGING(log); - } - - /* - * Check revocation status, but only if the cert we are checking - * is not a status reponder itself. We only do this in the case - * where we checked the cert chain (above); explicit trust "wins" - * (avoids status checking, just as it avoids CRL checking, which - * is all done inside VerifyCertChain) by bypassing this code. - */ - statusConfig = CERT_GetStatusConfig(handle); - if (certUsage != certUsageStatusResponder && statusConfig != NULL) { - if (statusConfig->statusChecker != NULL) { - rv = (* statusConfig->statusChecker)(handle, cert, - t, wincx); - if (rv != SECSuccess) { - LOG_ERROR_OR_EXIT(log,cert,0,0); - } - } - } - -winner: - return(SECSuccess); - -loser: - rv = SECFailure; - - return(rv); -} - -/* - * verify a certificate by checking if its valid and that we - * trust the issuer. Verify time against now. - */ -SECStatus -CERT_VerifyCertificateNow(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertificateUsage requiredUsages, - void *wincx, SECCertificateUsage* returnedUsages) -{ - return(CERT_VerifyCertificate(handle, cert, checkSig, - requiredUsages, PR_Now(), wincx, NULL, returnedUsages)); -} - -/* obsolete, do not use for new code */ -SECStatus -CERT_VerifyCertNow(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool checkSig, SECCertUsage certUsage, void *wincx) -{ - return(CERT_VerifyCert(handle, cert, checkSig, - certUsage, PR_Now(), wincx, NULL)); -} - - -/* [ FROM pcertdb.c ] */ -/* - * Supported usage values and types: - * certUsageSSLClient - * certUsageSSLServer - * certUsageSSLServerWithStepUp - * certUsageEmailSigner - * certUsageEmailRecipient - * certUsageObjectSigner - */ - -CERTCertificate * -CERT_FindMatchingCert(CERTCertDBHandle *handle, SECItem *derName, - CERTCertOwner owner, SECCertUsage usage, - PRBool preferTrusted, int64 validTime, PRBool validOnly) -{ - CERTCertList *certList = NULL; - CERTCertificate *cert = NULL; - unsigned int requiredTrustFlags; - SECTrustType requiredTrustType; - unsigned int flags; - - PRBool lookingForCA = PR_FALSE; - SECStatus rv; - CERTCertListNode *node; - CERTCertificate *saveUntrustedCA = NULL; - - /* if preferTrusted is set, must be a CA cert */ - PORT_Assert( ! ( preferTrusted && ( owner != certOwnerCA ) ) ); - - if ( owner == certOwnerCA ) { - lookingForCA = PR_TRUE; - if ( preferTrusted ) { - rv = CERT_TrustFlagsForCACertUsage(usage, &requiredTrustFlags, - &requiredTrustType); - if ( rv != SECSuccess ) { - goto loser; - } - requiredTrustFlags |= CERTDB_VALID_CA; - } - } - - certList = CERT_CreateSubjectCertList(NULL, handle, derName, validTime, - validOnly); - if ( certList != NULL ) { - rv = CERT_FilterCertListByUsage(certList, usage, lookingForCA); - if ( rv != SECSuccess ) { - goto loser; - } - - node = CERT_LIST_HEAD(certList); - - while ( !CERT_LIST_END(node, certList) ) { - cert = node->cert; - - /* looking for a trusted CA cert */ - if ( ( owner == certOwnerCA ) && preferTrusted && - ( requiredTrustType != trustTypeNone ) ) { - - if ( cert->trust == NULL ) { - flags = 0; - } else { - flags = SEC_GET_TRUST_FLAGS(cert->trust, requiredTrustType); - } - - if ( ( flags & requiredTrustFlags ) != requiredTrustFlags ) { - /* cert is not trusted */ - /* if this is the first cert to get this far, then save - * it, so we can use it if we can't find a trusted one - */ - if ( saveUntrustedCA == NULL ) { - saveUntrustedCA = cert; - } - goto endloop; - } - } - /* if we got this far, then this cert meets all criteria */ - break; - -endloop: - node = CERT_LIST_NEXT(node); - cert = NULL; - } - - /* use the saved one if we have it */ - if ( cert == NULL ) { - cert = saveUntrustedCA; - } - - /* if we found one then bump the ref count before freeing the list */ - if ( cert != NULL ) { - /* bump the ref count */ - cert = CERT_DupCertificate(cert); - } - - CERT_DestroyCertList(certList); - } - - return(cert); - -loser: - if ( certList != NULL ) { - CERT_DestroyCertList(certList); - } - - return(NULL); -} - - -/* [ From certdb.c ] */ -/* - * Filter a list of certificates, removing those certs that do not have - * one of the named CA certs somewhere in their cert chain. - * - * "certList" - the list of certificates to filter - * "nCANames" - number of CA names - * "caNames" - array of CA names in string(rfc 1485) form - * "usage" - what use the certs are for, this is used when - * selecting CA certs - */ -SECStatus -CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames, - char **caNames, SECCertUsage usage) -{ - CERTCertificate *issuerCert = NULL; - CERTCertificate *subjectCert; - CERTCertListNode *node, *freenode; - CERTCertificate *cert; - int n; - char **names; - PRBool found; - int64 time; - - if ( nCANames <= 0 ) { - return(SECSuccess); - } - - time = PR_Now(); - - node = CERT_LIST_HEAD(certList); - - while ( ! CERT_LIST_END(node, certList) ) { - cert = node->cert; - - subjectCert = CERT_DupCertificate(cert); - - /* traverse the CA certs for this cert */ - found = PR_FALSE; - while ( subjectCert != NULL ) { - n = nCANames; - names = caNames; - - if (subjectCert->issuerName != NULL) { - while ( n > 0 ) { - if ( PORT_Strcmp(*names, subjectCert->issuerName) == 0 ) { - found = PR_TRUE; - break; - } - - n--; - names++; - } - } - - if ( found ) { - break; - } - - issuerCert = CERT_FindCertIssuer(subjectCert, time, usage); - if ( issuerCert == subjectCert ) { - CERT_DestroyCertificate(issuerCert); - issuerCert = NULL; - break; - } - CERT_DestroyCertificate(subjectCert); - subjectCert = issuerCert; - - } - CERT_DestroyCertificate(subjectCert); - if ( !found ) { - /* CA was not found, so remove this cert from the list */ - freenode = node; - node = CERT_LIST_NEXT(node); - CERT_RemoveCertListNode(freenode); - } else { - /* CA was found, so leave it in the list */ - node = CERT_LIST_NEXT(node); - } - } - - return(SECSuccess); -} - -/* - * Given a certificate, return a string containing the nickname, and possibly - * one of the validity strings, based on the current validity state of the - * certificate. - * - * "arena" - arena to allocate returned string from. If NULL, then heap - * is used. - * "cert" - the cert to get nickname from - * "expiredString" - the string to append to the nickname if the cert is - * expired. - * "notYetGoodString" - the string to append to the nickname if the cert is - * not yet good. - */ -char * -CERT_GetCertNicknameWithValidity(PRArenaPool *arena, CERTCertificate *cert, - char *expiredString, char *notYetGoodString) -{ - SECCertTimeValidity validity; - char *nickname = NULL, *tmpstr = NULL; - - validity = CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE); - - /* if the cert is good, then just use the nickname directly */ - if ( validity == secCertTimeValid ) { - if ( arena == NULL ) { - nickname = PORT_Strdup(cert->nickname); - } else { - nickname = PORT_ArenaStrdup(arena, cert->nickname); - } - - if ( nickname == NULL ) { - goto loser; - } - } else { - - /* if the cert is not valid, then tack one of the strings on the - * end - */ - if ( validity == secCertTimeExpired ) { - tmpstr = PR_smprintf("%s%s", cert->nickname, - expiredString); - } else if ( validity == secCertTimeNotValidYet ) { - /* not yet valid */ - tmpstr = PR_smprintf("%s%s", cert->nickname, - notYetGoodString); - } else { - /* undetermined */ - tmpstr = PR_smprintf("%s", - "(NULL) (Validity Unknown)"); - } - - if ( tmpstr == NULL ) { - goto loser; - } - - if ( arena ) { - /* copy the string into the arena and free the malloc'd one */ - nickname = PORT_ArenaStrdup(arena, tmpstr); - PORT_Free(tmpstr); - } else { - nickname = tmpstr; - } - if ( nickname == NULL ) { - goto loser; - } - } - return(nickname); - -loser: - return(NULL); -} - -/* - * Collect the nicknames from all certs in a CertList. If the cert is not - * valid, append a string to that nickname. - * - * "certList" - the list of certificates - * "expiredString" - the string to append to the nickname of any expired cert - * "notYetGoodString" - the string to append to the nickname of any cert - * that is not yet valid - */ -CERTCertNicknames * -CERT_NicknameStringsFromCertList(CERTCertList *certList, char *expiredString, - char *notYetGoodString) -{ - CERTCertNicknames *names; - PRArenaPool *arena; - CERTCertListNode *node; - char **nn; - - /* allocate an arena */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( arena == NULL ) { - return(NULL); - } - - /* allocate the structure */ - names = PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames)); - if ( names == NULL ) { - goto loser; - } - - /* init the structure */ - names->arena = arena; - names->head = NULL; - names->numnicknames = 0; - names->nicknames = NULL; - names->totallen = 0; - - /* count the certs in the list */ - node = CERT_LIST_HEAD(certList); - while ( ! CERT_LIST_END(node, certList) ) { - names->numnicknames++; - node = CERT_LIST_NEXT(node); - } - - /* allocate nicknames array */ - names->nicknames = PORT_ArenaAlloc(arena, - sizeof(char *) * names->numnicknames); - if ( names->nicknames == NULL ) { - goto loser; - } - - /* just in case printf can't deal with null strings */ - if (expiredString == NULL ) { - expiredString = ""; - } - - if ( notYetGoodString == NULL ) { - notYetGoodString = ""; - } - - /* traverse the list of certs and collect the nicknames */ - nn = names->nicknames; - node = CERT_LIST_HEAD(certList); - while ( ! CERT_LIST_END(node, certList) ) { - *nn = CERT_GetCertNicknameWithValidity(arena, node->cert, - expiredString, - notYetGoodString); - if ( *nn == NULL ) { - goto loser; - } - - names->totallen += PORT_Strlen(*nn); - - nn++; - node = CERT_LIST_NEXT(node); - } - - return(names); - -loser: - PORT_FreeArena(arena, PR_FALSE); - return(NULL); -} - -/* - * Extract the nickname from a nickmake string that may have either - * expiredString or notYetGoodString appended. - * - * Args: - * "namestring" - the string containing the nickname, and possibly - * one of the validity label strings - * "expiredString" - the expired validity label string - * "notYetGoodString" - the not yet good validity label string - * - * Returns the raw nickname - */ -char * -CERT_ExtractNicknameString(char *namestring, char *expiredString, - char *notYetGoodString) -{ - int explen, nyglen, namelen; - int retlen; - char *retstr; - - namelen = PORT_Strlen(namestring); - explen = PORT_Strlen(expiredString); - nyglen = PORT_Strlen(notYetGoodString); - - if ( namelen > explen ) { - if ( PORT_Strcmp(expiredString, &namestring[namelen-explen]) == 0 ) { - retlen = namelen - explen; - retstr = (char *)PORT_Alloc(retlen+1); - if ( retstr == NULL ) { - goto loser; - } - - PORT_Memcpy(retstr, namestring, retlen); - retstr[retlen] = '\0'; - goto done; - } - } - - if ( namelen > nyglen ) { - if ( PORT_Strcmp(notYetGoodString, &namestring[namelen-nyglen]) == 0) { - retlen = namelen - nyglen; - retstr = (char *)PORT_Alloc(retlen+1); - if ( retstr == NULL ) { - goto loser; - } - - PORT_Memcpy(retstr, namestring, retlen); - retstr[retlen] = '\0'; - goto done; - } - } - - /* if name string is shorter than either invalid string, then it must - * be a raw nickname - */ - retstr = PORT_Strdup(namestring); - -done: - return(retstr); - -loser: - return(NULL); -} - -CERTCertList * -CERT_GetCertChainFromCert(CERTCertificate *cert, int64 time, SECCertUsage usage) -{ - CERTCertList *chain = NULL; - - if (NULL == cert) { - return NULL; - } - - cert = CERT_DupCertificate(cert); - if (NULL == cert) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - chain = CERT_NewCertList(); - if (NULL == chain) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - - while (cert != NULL) { - if (SECSuccess != CERT_AddCertToListTail(chain, cert)) { - /* return partial chain */ - PORT_SetError(SEC_ERROR_NO_MEMORY); - return chain; - } - - if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) - == SECEqual) { - /* return complete chain */ - return chain; - } - - cert = CERT_FindCertIssuer(cert, time, usage); - } - - /* return partial chain */ - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - return chain; -} diff --git a/security/nss/lib/certhigh/config.mk b/security/nss/lib/certhigh/config.mk deleted file mode 100644 index 665828c63..000000000 --- a/security/nss/lib/certhigh/config.mk +++ /dev/null @@ -1,47 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Netscape security libraries. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** - -# -# Override TARGETS variable so that only static libraries -# are specifed as dependencies within rules.mk. -# - -TARGETS = $(LIBRARY) -SHARED_LIBRARY = -IMPORT_LIBRARY = -PROGRAM = - diff --git a/security/nss/lib/certhigh/crlv2.c b/security/nss/lib/certhigh/crlv2.c deleted file mode 100644 index b6d8c9182..000000000 --- a/security/nss/lib/certhigh/crlv2.c +++ /dev/null @@ -1,141 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Code for dealing with x.509 v3 crl and crl entries extensions. - * - * $Id$ - */ - -#include "cert.h" -#include "secitem.h" -#include "secoid.h" -#include "secoidt.h" -#include "secder.h" -#include "secasn1.h" -#include "certxutl.h" - -SECStatus -CERT_FindCRLExtensionByOID(CERTCrl *crl, SECItem *oid, SECItem *value) -{ - return (cert_FindExtensionByOID (crl->extensions, oid, value)); -} - - -SECStatus -CERT_FindCRLExtension(CERTCrl *crl, int tag, SECItem *value) -{ - return (cert_FindExtension (crl->extensions, tag, value)); -} - - -/* Callback to set extensions and adjust verison */ -static void -SetCrlExts(void *object, CERTCertExtension **exts) -{ - CERTCrl *crl = (CERTCrl *)object; - - crl->extensions = exts; - DER_SetUInteger (crl->arena, &crl->version, SEC_CRL_VERSION_2); -} - -void * -CERT_StartCRLExtensions(CERTCrl *crl) -{ - return (cert_StartExtensions ((void *)crl, crl->arena, SetCrlExts)); -} - -static void -SetCrlEntryExts(void *object, CERTCertExtension **exts) -{ - CERTCrlEntry *crlEntry = (CERTCrlEntry *)object; - - crlEntry->extensions = exts; -} - -void * -CERT_StartCRLEntryExtensions(CERTCrl *crl, CERTCrlEntry *entry) -{ - return (cert_StartExtensions (entry, crl->arena, SetCrlEntryExts)); -} - -SECStatus CERT_FindCRLNumberExten (CERTCrl *crl, CERTCrlNumber *value) -{ - SECItem encodedExtenValue; - SECStatus rv; - - encodedExtenValue.data = NULL; - encodedExtenValue.len = 0; - - rv = cert_FindExtension - (crl->extensions, SEC_OID_X509_CRL_NUMBER, &encodedExtenValue); - if ( rv != SECSuccess ) - return (rv); - - rv = SEC_ASN1DecodeItem (NULL, value, SEC_IntegerTemplate, - &encodedExtenValue); - PORT_Free (encodedExtenValue.data); - return (rv); -} - -SECStatus CERT_FindCRLReasonExten (CERTCrl *crl, SECItem *value) -{ - return (CERT_FindBitStringExtension - (crl->extensions, SEC_OID_X509_REASON_CODE, value)); -} - -SECStatus CERT_FindInvalidDateExten (CERTCrl *crl, int64 *value) -{ - SECItem encodedExtenValue; - SECItem decodedExtenValue = {siBuffer,0}; - SECStatus rv; - - encodedExtenValue.data = decodedExtenValue.data = NULL; - encodedExtenValue.len = decodedExtenValue.len = 0; - - rv = cert_FindExtension - (crl->extensions, SEC_OID_X509_INVALID_DATE, &encodedExtenValue); - if ( rv != SECSuccess ) - return (rv); - - rv = SEC_ASN1DecodeItem (NULL, &decodedExtenValue, - SEC_GeneralizedTimeTemplate, &encodedExtenValue); - if (rv == SECSuccess) - rv = DER_GeneralizedTimeToTime(value, &encodedExtenValue); - PORT_Free (decodedExtenValue.data); - PORT_Free (encodedExtenValue.data); - return (rv); -} diff --git a/security/nss/lib/certhigh/manifest.mn b/security/nss/lib/certhigh/manifest.mn deleted file mode 100644 index 98eb9876d..000000000 --- a/security/nss/lib/certhigh/manifest.mn +++ /dev/null @@ -1,64 +0,0 @@ -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Netscape security libraries. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** -CORE_DEPTH = ../../.. - -EXPORTS = \ - ocsp.h \ - ocspt.h \ - $(NULL) - -PRIVATE_EXPORTS = \ - ocspti.h \ - ocspi.h \ - $(NULL) - -MODULE = nss - -CSRCS = \ - certhtml.c \ - certreq.c \ - crlv2.c \ - ocsp.c \ - certhigh.c \ - certvfy.c \ - xcrldist.c \ - $(NULL) - -REQUIRES = dbm - -LIBRARY_NAME = certhi - diff --git a/security/nss/lib/certhigh/ocsp.c b/security/nss/lib/certhigh/ocsp.c deleted file mode 100644 index 183f9b902..000000000 --- a/security/nss/lib/certhigh/ocsp.c +++ /dev/null @@ -1,4179 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Implementation of OCSP services, for both client and server. - * (XXX, really, mostly just for client right now, but intended to do both.) - * - * $Id$ - */ - -#include "prerror.h" -#include "prprf.h" -#include "plarena.h" -#include "prnetdb.h" - -#include "seccomon.h" -#include "secitem.h" -#include "secoidt.h" -#include "secasn1.h" -#include "secder.h" -#include "cert.h" -#include "xconst.h" -#include "secerr.h" -#include "secoid.h" -#include "hasht.h" -#include "sechash.h" -#include "secasn1.h" -#include "keyhi.h" -#include "cryptohi.h" -#include "ocsp.h" -#include "ocspti.h" -#include "genname.h" -#include "certxutl.h" -#include "pk11func.h" /* for PK11_HashBuf */ -#include <stdarg.h> - - -static struct OCSPGlobalStruct { - PRLock *lock; - const SEC_HttpClientFcn *defaultHttpClientFcn; -} OCSP_Global = { NULL, NULL }; - -SECStatus -SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable) -{ - if (!OCSP_Global.lock) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - PR_Lock(OCSP_Global.lock); - OCSP_Global.defaultHttpClientFcn = fcnTable; - PR_Unlock(OCSP_Global.lock); - - return SECSuccess; -} - -/* this function is called at NSS initialization time */ -SECStatus InitOCSPGlobal(void) -{ - if (OCSP_Global.lock != NULL) { - /* already initialized */ - return SECSuccess; - } - - OCSP_Global.lock = PR_NewLock(); - - return (OCSP_Global.lock) ? SECSuccess : SECFailure; -} - -/* - * A return value of NULL means: - * The application did not register it's own HTTP client. - */ -static const SEC_HttpClientFcn *GetRegisteredHttpClient() -{ - const SEC_HttpClientFcn *retval; - - if (!OCSP_Global.lock) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return NULL; - } - - PR_Lock(OCSP_Global.lock); - retval = OCSP_Global.defaultHttpClientFcn; - PR_Unlock(OCSP_Global.lock); - - return retval; -} - -/* - * The following structure is only used internally. It is allocated when - * someone turns on OCSP checking, and hangs off of the status-configuration - * structure in the certdb structure. We use it to keep configuration - * information specific to OCSP checking. - */ -typedef struct ocspCheckingContextStr { - PRBool useDefaultResponder; - char *defaultResponderURI; - char *defaultResponderNickname; - CERTCertificate *defaultResponderCert; -} ocspCheckingContext; - - -/* - * Forward declarations of sub-types, so I can lay out the types in the - * same order as the ASN.1 is laid out in the OCSP spec itself. - * - * These are in alphabetical order (case-insensitive); please keep it that way! - */ -extern const SEC_ASN1Template ocsp_CertIDTemplate[]; -extern const SEC_ASN1Template ocsp_PointerToSignatureTemplate[]; -extern const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[]; -extern const SEC_ASN1Template ocsp_ResponseDataTemplate[]; -extern const SEC_ASN1Template ocsp_RevokedInfoTemplate[]; -extern const SEC_ASN1Template ocsp_SingleRequestTemplate[]; -extern const SEC_ASN1Template ocsp_SingleResponseTemplate[]; -extern const SEC_ASN1Template ocsp_TBSRequestTemplate[]; - - -/* - * Request-related templates... - */ - -/* - * OCSPRequest ::= SEQUENCE { - * tbsRequest TBSRequest, - * optionalSignature [0] EXPLICIT Signature OPTIONAL } - */ -static const SEC_ASN1Template ocsp_OCSPRequestTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTOCSPRequest) }, - { SEC_ASN1_POINTER, - offsetof(CERTOCSPRequest, tbsRequest), - ocsp_TBSRequestTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(CERTOCSPRequest, optionalSignature), - ocsp_PointerToSignatureTemplate }, - { 0 } -}; - -/* - * TBSRequest ::= SEQUENCE { - * version [0] EXPLICIT Version DEFAULT v1, - * requestorName [1] EXPLICIT GeneralName OPTIONAL, - * requestList SEQUENCE OF Request, - * requestExtensions [2] EXPLICIT Extensions OPTIONAL } - * - * Version ::= INTEGER { v1(0) } - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_TBSRequestTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspTBSRequest) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspTBSRequest, version), - SEC_IntegerTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(ocspTBSRequest, derRequestorName), - SEC_PointerToAnyTemplate }, - { SEC_ASN1_SEQUENCE_OF, - offsetof(ocspTBSRequest, requestList), - ocsp_SingleRequestTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2, - offsetof(ocspTBSRequest, requestExtensions), - CERT_SequenceOfCertExtensionTemplate }, - { 0 } -}; - -/* - * Signature ::= SEQUENCE { - * signatureAlgorithm AlgorithmIdentifier, - * signature BIT STRING, - * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } - */ -static const SEC_ASN1Template ocsp_SignatureTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspSignature) }, - { SEC_ASN1_INLINE, - offsetof(ocspSignature, signatureAlgorithm), - SECOID_AlgorithmIDTemplate }, - { SEC_ASN1_BIT_STRING, - offsetof(ocspSignature, signature) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspSignature, derCerts), - SEC_SequenceOfAnyTemplate }, - { 0 } -}; - -/* - * This template is just an extra level to use in an explicitly-tagged - * reference to a Signature. - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_PointerToSignatureTemplate[] = { - { SEC_ASN1_POINTER, 0, ocsp_SignatureTemplate } -}; - -/* - * Request ::= SEQUENCE { - * reqCert CertID, - * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_SingleRequestTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspSingleRequest) }, - { SEC_ASN1_POINTER, - offsetof(ocspSingleRequest, reqCert), - ocsp_CertIDTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspSingleRequest, singleRequestExtensions), - CERT_SequenceOfCertExtensionTemplate }, - { 0 } -}; - - -/* - * This data structure and template (CertID) is used by both OCSP - * requests and responses. It is the only one that is shared. - * - * CertID ::= SEQUENCE { - * hashAlgorithm AlgorithmIdentifier, - * issuerNameHash OCTET STRING, -- Hash of Issuer DN - * issuerKeyHash OCTET STRING, -- Hash of Issuer public key - * serialNumber CertificateSerialNumber } - * - * CertificateSerialNumber ::= INTEGER - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_CertIDTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTOCSPCertID) }, - { SEC_ASN1_INLINE, - offsetof(CERTOCSPCertID, hashAlgorithm), - SECOID_AlgorithmIDTemplate }, - { SEC_ASN1_OCTET_STRING, - offsetof(CERTOCSPCertID, issuerNameHash) }, - { SEC_ASN1_OCTET_STRING, - offsetof(CERTOCSPCertID, issuerKeyHash) }, - { SEC_ASN1_INTEGER, - offsetof(CERTOCSPCertID, serialNumber) }, - { 0 } -}; - - -/* - * Response-related templates... - */ - -/* - * OCSPResponse ::= SEQUENCE { - * responseStatus OCSPResponseStatus, - * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } - */ -static const SEC_ASN1Template ocsp_OCSPResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTOCSPResponse) }, - { SEC_ASN1_ENUMERATED, - offsetof(CERTOCSPResponse, responseStatus) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(CERTOCSPResponse, responseBytes), - ocsp_PointerToResponseBytesTemplate }, - { 0 } -}; - -/* - * ResponseBytes ::= SEQUENCE { - * responseType OBJECT IDENTIFIER, - * response OCTET STRING } - */ -static const SEC_ASN1Template ocsp_ResponseBytesTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspResponseBytes) }, - { SEC_ASN1_OBJECT_ID, - offsetof(ocspResponseBytes, responseType) }, - { SEC_ASN1_OCTET_STRING, - offsetof(ocspResponseBytes, response) }, - { 0 } -}; - -/* - * This template is just an extra level to use in an explicitly-tagged - * reference to a ResponseBytes. - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_PointerToResponseBytesTemplate[] = { - { SEC_ASN1_POINTER, 0, ocsp_ResponseBytesTemplate } -}; - -/* - * BasicOCSPResponse ::= SEQUENCE { - * tbsResponseData ResponseData, - * signatureAlgorithm AlgorithmIdentifier, - * signature BIT STRING, - * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } - */ -static const SEC_ASN1Template ocsp_BasicOCSPResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspBasicOCSPResponse) }, - { SEC_ASN1_POINTER, - offsetof(ocspBasicOCSPResponse, tbsResponseData), - ocsp_ResponseDataTemplate }, - { SEC_ASN1_INLINE, - offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm), - SECOID_AlgorithmIDTemplate }, - { SEC_ASN1_BIT_STRING, - offsetof(ocspBasicOCSPResponse, responseSignature.signature) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspBasicOCSPResponse, responseSignature.derCerts), - SEC_SequenceOfAnyTemplate }, - { 0 } -}; - -/* - * ResponseData ::= SEQUENCE { - * version [0] EXPLICIT Version DEFAULT v1, - * responderID ResponderID, - * producedAt GeneralizedTime, - * responses SEQUENCE OF SingleResponse, - * responseExtensions [1] EXPLICIT Extensions OPTIONAL } - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_ResponseDataTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspResponseData) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspResponseData, version), - SEC_IntegerTemplate }, - { SEC_ASN1_ANY, - offsetof(ocspResponseData, derResponderID) }, - { SEC_ASN1_GENERALIZED_TIME, - offsetof(ocspResponseData, producedAt) }, - { SEC_ASN1_SEQUENCE_OF, - offsetof(ocspResponseData, responses), - ocsp_SingleResponseTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(ocspResponseData, responseExtensions), - CERT_SequenceOfCertExtensionTemplate }, - { 0 } -}; - -/* - * ResponderID ::= CHOICE { - * byName [1] EXPLICIT Name, - * byKey [2] EXPLICIT KeyHash } - * - * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key - * (excluding the tag and length fields) - * - * XXX Because the ASN.1 encoder and decoder currently do not provide - * a way to automatically handle a CHOICE, we need to do it in two - * steps, looking at the type tag and feeding the exact choice back - * to the ASN.1 code. Hopefully that will change someday and this - * can all be simplified down into a single template. Anyway, for - * now we list each choice as its own template: - */ -static const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[] = { - { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(ocspResponderID, responderIDValue.name), - CERT_NameTemplate } -}; -static const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[] = { - { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2, - offsetof(ocspResponderID, responderIDValue.keyHash), - SEC_OctetStringTemplate } -}; -static const SEC_ASN1Template ocsp_ResponderIDOtherTemplate[] = { - { SEC_ASN1_ANY, - offsetof(ocspResponderID, responderIDValue.other) } -}; - -/* - * SingleResponse ::= SEQUENCE { - * certID CertID, - * certStatus CertStatus, - * thisUpdate GeneralizedTime, - * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, - * singleExtensions [1] EXPLICIT Extensions OPTIONAL } - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_SingleResponseTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(CERTOCSPSingleResponse) }, - { SEC_ASN1_POINTER, - offsetof(CERTOCSPSingleResponse, certID), - ocsp_CertIDTemplate }, - { SEC_ASN1_ANY, - offsetof(CERTOCSPSingleResponse, derCertStatus) }, - { SEC_ASN1_GENERALIZED_TIME, - offsetof(CERTOCSPSingleResponse, thisUpdate) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(CERTOCSPSingleResponse, nextUpdate), - SEC_PointerToGeneralizedTimeTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(CERTOCSPSingleResponse, singleExtensions), - CERT_SequenceOfCertExtensionTemplate }, - { 0 } -}; - -/* - * CertStatus ::= CHOICE { - * good [0] IMPLICIT NULL, - * revoked [1] IMPLICIT RevokedInfo, - * unknown [2] IMPLICIT UnknownInfo } - * - * Because the ASN.1 encoder and decoder currently do not provide - * a way to automatically handle a CHOICE, we need to do it in two - * steps, looking at the type tag and feeding the exact choice back - * to the ASN.1 code. Hopefully that will change someday and this - * can all be simplified down into a single template. Anyway, for - * now we list each choice as its own template: - */ -static const SEC_ASN1Template ocsp_CertStatusGoodTemplate[] = { - { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspCertStatus, certStatusInfo.goodInfo), - SEC_NullTemplate } -}; -static const SEC_ASN1Template ocsp_CertStatusRevokedTemplate[] = { - { SEC_ASN1_POINTER | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(ocspCertStatus, certStatusInfo.revokedInfo), - ocsp_RevokedInfoTemplate } -}; -static const SEC_ASN1Template ocsp_CertStatusUnknownTemplate[] = { - { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | 2, - offsetof(ocspCertStatus, certStatusInfo.unknownInfo), - SEC_NullTemplate } -}; -static const SEC_ASN1Template ocsp_CertStatusOtherTemplate[] = { - { SEC_ASN1_POINTER, - offsetof(ocspCertStatus, certStatusInfo.otherInfo), - SEC_AnyTemplate } -}; - -/* - * RevokedInfo ::= SEQUENCE { - * revocationTime GeneralizedTime, - * revocationReason [0] EXPLICIT CRLReason OPTIONAL } - * - * Note: this should be static but the AIX compiler doesn't like it (because it - * was forward-declared above); it is not meant to be exported, but this - * is the only way it will compile. - */ -const SEC_ASN1Template ocsp_RevokedInfoTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspRevokedInfo) }, - { SEC_ASN1_GENERALIZED_TIME, - offsetof(ocspRevokedInfo, revocationTime) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(ocspRevokedInfo, revocationReason), - SEC_PointerToEnumeratedTemplate }, - { 0 } -}; - - -/* - * OCSP-specific extension templates: - */ - -/* - * ServiceLocator ::= SEQUENCE { - * issuer Name, - * locator AuthorityInfoAccessSyntax OPTIONAL } - */ -static const SEC_ASN1Template ocsp_ServiceLocatorTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(ocspServiceLocator) }, - { SEC_ASN1_POINTER, - offsetof(ocspServiceLocator, issuer), - CERT_NameTemplate }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, - offsetof(ocspServiceLocator, locator) }, - { 0 } -}; - - -/* - * REQUEST SUPPORT FUNCTIONS (encode/create/decode/destroy): - */ - -/* - * FUNCTION: CERT_EncodeOCSPRequest - * DER encodes an OCSP Request, possibly adding a signature as well. - * XXX Signing is not yet supported, however; see comments in code. - * INPUTS: - * PRArenaPool *arena - * The return value is allocated from here. - * If a NULL is passed in, allocation is done from the heap instead. - * CERTOCSPRequest *request - * The request to be encoded. - * void *pwArg - * Pointer to argument for password prompting, if needed. (Definitely - * not needed if not signing.) - * RETURN: - * Returns a NULL on error and a pointer to the SECItem with the - * encoded value otherwise. Any error is likely to be low-level - * (e.g. no memory). - */ -SECItem * -CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, - void *pwArg) -{ - ocspTBSRequest *tbsRequest; - SECStatus rv; - - /* XXX All of these should generate errors if they fail. */ - PORT_Assert(request); - PORT_Assert(request->tbsRequest); - - tbsRequest = request->tbsRequest; - - if (request->tbsRequest->extensionHandle != NULL) { - rv = CERT_FinishExtensions(request->tbsRequest->extensionHandle); - request->tbsRequest->extensionHandle = NULL; - if (rv != SECSuccess) - return NULL; - } - - /* - * XXX When signed requests are supported and request->optionalSignature - * is not NULL: - * - need to encode tbsRequest->requestorName - * - need to encode tbsRequest - * - need to sign that encoded result (using cert in sig), filling in the - * request->optionalSignature structure with the result, the signing - * algorithm and (perhaps?) the cert (and its chain?) in derCerts - */ - - return SEC_ASN1EncodeItem(arena, NULL, request, ocsp_OCSPRequestTemplate); -} - - -/* - * FUNCTION: CERT_DecodeOCSPRequest - * Decode a DER encoded OCSP Request. - * INPUTS: - * SECItem *src - * Pointer to a SECItem holding DER encoded OCSP Request. - * RETURN: - * Returns a pointer to a CERTOCSPRequest containing the decoded request. - * On error, returns NULL. Most likely error is trouble decoding - * (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory). - */ -CERTOCSPRequest * -CERT_DecodeOCSPRequest(SECItem *src) -{ - PRArenaPool *arena = NULL; - SECStatus rv = SECFailure; - CERTOCSPRequest *dest = NULL; - int i; - SECItem newSrc; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto loser; - } - dest = (CERTOCSPRequest *) PORT_ArenaZAlloc(arena, - sizeof(CERTOCSPRequest)); - if (dest == NULL) { - goto loser; - } - dest->arena = arena; - - /* copy the DER into the arena, since Quick DER returns data that points - into the DER input, which may get freed by the caller */ - rv = SECITEM_CopyItem(arena, &newSrc, src); - if ( rv != SECSuccess ) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(arena, dest, ocsp_OCSPRequestTemplate, &newSrc); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); - goto loser; - } - - /* - * XXX I would like to find a way to get rid of the necessity - * of doing this copying of the arena pointer. - */ - for (i = 0; dest->tbsRequest->requestList[i] != NULL; i++) { - dest->tbsRequest->requestList[i]->arena = arena; - } - - return dest; - -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -} - -SECStatus -CERT_DestroyOCSPCertID(CERTOCSPCertID* certID) -{ - if (certID->poolp) { - PORT_FreeArena(certID->poolp, PR_FALSE); - return SECSuccess; - } - return SECFailure; -} - - -/* - * Create and fill-in a CertID. This function fills in the hash values - * (issuerNameHash and issuerKeyHash), and is hardwired to use SHA1. - * Someday it might need to be more flexible about hash algorithm, but - * for now we have no intention/need to create anything else. - * - * Error causes a null to be returned; most likely cause is trouble - * finding the certificate issuer (SEC_ERROR_UNKNOWN_ISSUER). - * Other errors are low-level problems (no memory, bad database, etc.). - */ -static CERTOCSPCertID * -ocsp_CreateCertID(PRArenaPool *arena, CERTCertificate *cert, int64 time) -{ - CERTOCSPCertID *certID; - CERTCertificate *issuerCert = NULL; - SECItem *tempItem = NULL; - void *mark = PORT_ArenaMark(arena); - SECStatus rv; - - PORT_Assert(arena != NULL); - - certID = PORT_ArenaZNew(arena, CERTOCSPCertID); - if (certID == NULL) { - goto loser; - } - - rv = SECOID_SetAlgorithmID(arena, &certID->hashAlgorithm, SEC_OID_SHA1, - NULL); - if (rv != SECSuccess) { - goto loser; - } - - issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); - if (issuerCert == NULL) { - goto loser; - } - - tempItem = SEC_ASN1EncodeItem(NULL, NULL, &issuerCert->subject, - CERT_NameTemplate); - if (tempItem == NULL) { - goto loser; - } - - if (SECITEM_AllocItem(arena, &(certID->issuerNameHash), - SHA1_LENGTH) == NULL) { - goto loser; - } - rv = PK11_HashBuf(SEC_OID_SHA1, certID->issuerNameHash.data, - tempItem->data, tempItem->len); - if (rv != SECSuccess) { - goto loser; - } - certID->issuerSHA1NameHash.data = certID->issuerNameHash.data; - certID->issuerSHA1NameHash.len = certID->issuerNameHash.len; - /* cache the other two hash algorithms as well */ - if (SECITEM_AllocItem(arena, &(certID->issuerMD5NameHash), - MD5_LENGTH) == NULL) { - goto loser; - } - rv = PK11_HashBuf(SEC_OID_MD5, certID->issuerMD5NameHash.data, - tempItem->data, tempItem->len); - if (rv != SECSuccess) { - goto loser; - } - if (SECITEM_AllocItem(arena, &(certID->issuerMD2NameHash), - MD2_LENGTH) == NULL) { - goto loser; - } - rv = PK11_HashBuf(SEC_OID_MD2, certID->issuerMD2NameHash.data, - tempItem->data, tempItem->len); - if (rv != SECSuccess) { - goto loser; - } - - SECITEM_FreeItem(tempItem, PR_TRUE); - tempItem = NULL; - - if (CERT_SPKDigestValueForCert(arena, issuerCert, SEC_OID_SHA1, - &(certID->issuerKeyHash)) == NULL) { - goto loser; - } - certID->issuerSHA1KeyHash.data = certID->issuerKeyHash.data; - certID->issuerSHA1KeyHash.len = certID->issuerKeyHash.len; - /* cache the other two hash algorithms as well */ - if (CERT_SPKDigestValueForCert(arena, issuerCert, SEC_OID_MD5, - &(certID->issuerMD5KeyHash)) == NULL) { - goto loser; - } - if (CERT_SPKDigestValueForCert(arena, issuerCert, SEC_OID_MD2, - &(certID->issuerMD2KeyHash)) == NULL) { - goto loser; - } - - - /* now we are done with issuerCert */ - CERT_DestroyCertificate(issuerCert); - issuerCert = NULL; - - rv = SECITEM_CopyItem(arena, &certID->serialNumber, &cert->serialNumber); - if (rv != SECSuccess) { - goto loser; - } - - PORT_ArenaUnmark(arena, mark); - return certID; - -loser: - if (issuerCert != NULL) { - CERT_DestroyCertificate(issuerCert); - } - if (tempItem != NULL) { - SECITEM_FreeItem(tempItem, PR_TRUE); - } - PORT_ArenaRelease(arena, mark); - return NULL; -} - -CERTOCSPCertID* -CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time) -{ - PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - CERTOCSPCertID *certID; - PORT_Assert(arena != NULL); - if (!arena) - return NULL; - - certID = ocsp_CreateCertID(arena, cert, time); - if (!certID) { - PORT_FreeArena(arena, PR_FALSE); - return NULL; - } - certID->poolp = arena; - return certID; -} - - - -/* - * Callback to set Extensions in request object - */ -void SetSingleReqExts(void *object, CERTCertExtension **exts) -{ - ocspSingleRequest *singleRequest = - (ocspSingleRequest *)object; - - singleRequest->singleRequestExtensions = exts; -} - -/* - * Add the Service Locator extension to the singleRequestExtensions - * for the given singleRequest. - * - * All errors are internal or low-level problems (e.g. no memory). - */ -static SECStatus -ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest, - CERTCertificate *cert) -{ - ocspServiceLocator *serviceLocator = NULL; - void *extensionHandle = NULL; - SECStatus rv = SECFailure; - - serviceLocator = PORT_ZNew(ocspServiceLocator); - if (serviceLocator == NULL) - goto loser; - - /* - * Normally it would be a bad idea to do a direct reference like - * this rather than allocate and copy the name *or* at least dup - * a reference of the cert. But all we need is to be able to read - * the issuer name during the encoding we are about to do, so a - * copy is just a waste of time. - */ - serviceLocator->issuer = &cert->issuer; - - rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, - &serviceLocator->locator); - if (rv != SECSuccess) { - if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) - goto loser; - } - - /* prepare for following loser gotos */ - rv = SECFailure; - PORT_SetError(0); - - extensionHandle = cert_StartExtensions(singleRequest, - singleRequest->arena, SetSingleReqExts); - if (extensionHandle == NULL) - goto loser; - - rv = CERT_EncodeAndAddExtension(extensionHandle, - SEC_OID_PKIX_OCSP_SERVICE_LOCATOR, - serviceLocator, PR_FALSE, - ocsp_ServiceLocatorTemplate); - -loser: - if (extensionHandle != NULL) { - /* - * Either way we have to finish out the extension context (so it gets - * freed). But careful not to override any already-set bad status. - */ - SECStatus tmprv = CERT_FinishExtensions(extensionHandle); - if (rv == SECSuccess) - rv = tmprv; - } - - /* - * Finally, free the serviceLocator structure itself and we are done. - */ - if (serviceLocator != NULL) { - if (serviceLocator->locator.data != NULL) - SECITEM_FreeItem(&serviceLocator->locator, PR_FALSE); - PORT_Free(serviceLocator); - } - - return rv; -} - -/* - * Creates an array of ocspSingleRequest based on a list of certs. - * Note that the code which later compares the request list with the - * response expects this array to be in the exact same order as the - * certs are found in the list. It would be harder to change that - * order than preserve it, but since the requirement is not obvious, - * it deserves to be mentioned. - * - * Any problem causes a null return and error set: - * SEC_ERROR_UNKNOWN_ISSUER - * Other errors are low-level problems (no memory, bad database, etc.). - */ -static ocspSingleRequest ** -ocsp_CreateSingleRequestList(PRArenaPool *arena, CERTCertList *certList, - int64 time, PRBool includeLocator) -{ - ocspSingleRequest **requestList = NULL; - CERTCertListNode *node; - int i, count; - void *mark = PORT_ArenaMark(arena); - - node = CERT_LIST_HEAD(certList); - for (count = 0; !CERT_LIST_END(node, certList); count++) { - node = CERT_LIST_NEXT(node); - } - - if (count == 0) - goto loser; - - requestList = PORT_ArenaNewArray(arena, ocspSingleRequest *, count + 1); - if (requestList == NULL) - goto loser; - - node = CERT_LIST_HEAD(certList); - for (i = 0; !CERT_LIST_END(node, certList); i++) { - requestList[i] = PORT_ArenaZNew(arena, ocspSingleRequest); - if (requestList[i] == NULL) - goto loser; - - requestList[i]->arena = arena; - requestList[i]->reqCert = ocsp_CreateCertID(arena, node->cert, time); - if (requestList[i]->reqCert == NULL) - goto loser; - - if (includeLocator == PR_TRUE) { - SECStatus rv; - - rv = ocsp_AddServiceLocatorExtension(requestList[i], node->cert); - if (rv != SECSuccess) - goto loser; - } - - node = CERT_LIST_NEXT(node); - } - - PORT_Assert(i == count); - - PORT_ArenaUnmark(arena, mark); - requestList[i] = NULL; - return requestList; - -loser: - PORT_ArenaRelease(arena, mark); - return NULL; -} - - -/* - * FUNCTION: CERT_CreateOCSPRequest - * Creates a CERTOCSPRequest, requesting the status of the certs in - * the given list. - * INPUTS: - * CERTCertList *certList - * A list of certs for which status will be requested. - * Note that all of these certificates should have the same issuer, - * or it's expected the response will be signed by a trusted responder. - * If the certs need to be broken up into multiple requests, that - * must be handled by the caller (and thus by having multiple calls - * to this routine), who knows about where the request(s) are being - * sent and whether there are any trusted responders in place. - * int64 time - * Indicates the time for which the certificate status is to be - * determined -- this may be used in the search for the cert's issuer - * but has no effect on the request itself. - * PRBool addServiceLocator - * If true, the Service Locator extension should be added to the - * single request(s) for each cert. - * CERTCertificate *signerCert - * If non-NULL, means sign the request using this cert. Otherwise, - * do not sign. - * XXX note that request signing is not yet supported; see comment in code - * RETURN: - * A pointer to a CERTOCSPRequest structure containing an OCSP request - * for the cert list. On error, null is returned, with an error set - * indicating the reason. This is likely SEC_ERROR_UNKNOWN_ISSUER. - * (The issuer is needed to create a request for the certificate.) - * Other errors are low-level problems (no memory, bad database, etc.). - */ -CERTOCSPRequest * -CERT_CreateOCSPRequest(CERTCertList *certList, int64 time, - PRBool addServiceLocator, - CERTCertificate *signerCert) -{ - PRArenaPool *arena = NULL; - CERTOCSPRequest *request = NULL; - ocspTBSRequest *tbsRequest = NULL; - - /* - * XXX This should set an error, but since it is only temporary and - * since PSM will not initially provide a way to turn on signing of - * requests anyway, I figure we can just skip defining an error that - * will be obsolete in the next release. When we are prepared to - * put signing of requests back in, this entire check will go away, - * and later in this function we will need to allocate a signature - * structure for the request, fill in the "derCerts" field in it, - * save the signerCert there, as well as fill in the "requestorName" - * field of the tbsRequest. - */ - if (signerCert != NULL) { - return NULL; - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto loser; - } - - request = PORT_ArenaZNew(arena, CERTOCSPRequest); - if (request == NULL) { - goto loser; - } - request->arena = arena; - - tbsRequest = PORT_ArenaZNew(arena, ocspTBSRequest); - if (tbsRequest == NULL) { - goto loser; - } - request->tbsRequest = tbsRequest; - - /* version 1 is the default, so we need not fill in a version number */ - - /* - * Now create the list of single requests, one for each cert. - */ - tbsRequest->requestList = ocsp_CreateSingleRequestList(arena, certList, - time, - addServiceLocator); - if (tbsRequest->requestList == NULL) { - goto loser; - } - return request; - -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -} - - -/* - * FUNCTION: CERT_AddOCSPAcceptableResponses - * Add the AcceptableResponses extension to an OCSP Request. - * INPUTS: - * CERTOCSPRequest *request - * The request to which the extension should be added. - * ... - * A list (of one or more) of SECOidTag -- each of the response types - * to be added. The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE. - * (This marks the end of the list, and it must be specified because a - * client conforming to the OCSP standard is required to handle the basic - * response type.) The OIDs are not checked in any way. - * RETURN: - * SECSuccess if the extension is added; SECFailure if anything goes wrong. - * All errors are internal or low-level problems (e.g. no memory). - */ - -void SetRequestExts(void *object, CERTCertExtension **exts) -{ - CERTOCSPRequest *request = (CERTOCSPRequest *)object; - - request->tbsRequest->requestExtensions = exts; -} - -SECStatus -CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request, - SECOidTag responseType0, ...) -{ - void *extHandle; - va_list ap; - int i, count; - SECOidTag responseType; - SECOidData *responseOid; - SECItem **acceptableResponses = NULL; - SECStatus rv = SECFailure; - - extHandle = request->tbsRequest->extensionHandle; - if (extHandle == NULL) { - extHandle = cert_StartExtensions(request, request->arena, SetRequestExts); - if (extHandle == NULL) - goto loser; - } - - /* Count number of OIDS going into the extension value. */ - count = 1; - if (responseType0 != SEC_OID_PKIX_OCSP_BASIC_RESPONSE) { - va_start(ap, responseType0); - do { - count++; - responseType = va_arg(ap, SECOidTag); - } while (responseType != SEC_OID_PKIX_OCSP_BASIC_RESPONSE); - va_end(ap); - } - - acceptableResponses = PORT_NewArray(SECItem *, count + 1); - if (acceptableResponses == NULL) - goto loser; - - i = 0; - responseOid = SECOID_FindOIDByTag(responseType0); - acceptableResponses[i++] = &(responseOid->oid); - if (count > 1) { - va_start(ap, responseType0); - for ( ; i < count; i++) { - responseType = va_arg(ap, SECOidTag); - responseOid = SECOID_FindOIDByTag(responseType); - acceptableResponses[i] = &(responseOid->oid); - } - va_end(ap); - } - acceptableResponses[i] = NULL; - - rv = CERT_EncodeAndAddExtension(extHandle, SEC_OID_PKIX_OCSP_RESPONSE, - &acceptableResponses, PR_FALSE, - SEC_SequenceOfObjectIDTemplate); - if (rv != SECSuccess) - goto loser; - - PORT_Free(acceptableResponses); - if (request->tbsRequest->extensionHandle == NULL) - request->tbsRequest->extensionHandle = extHandle; - return SECSuccess; - -loser: - if (acceptableResponses != NULL) - PORT_Free(acceptableResponses); - if (extHandle != NULL) - (void) CERT_FinishExtensions(extHandle); - return rv; -} - - -/* - * FUNCTION: CERT_DestroyOCSPRequest - * Frees an OCSP Request structure. - * INPUTS: - * CERTOCSPRequest *request - * Pointer to CERTOCSPRequest to be freed. - * RETURN: - * No return value; no errors. - */ -void -CERT_DestroyOCSPRequest(CERTOCSPRequest *request) -{ - if (request == NULL) - return; - - if (request->tbsRequest != NULL) { - if (request->tbsRequest->requestorName != NULL) - CERT_DestroyGeneralNameList(request->tbsRequest->requestorName); - if (request->tbsRequest->extensionHandle != NULL) - (void) CERT_FinishExtensions(request->tbsRequest->extensionHandle); - } - - if (request->optionalSignature != NULL) { - if (request->optionalSignature->cert != NULL) - CERT_DestroyCertificate(request->optionalSignature->cert); - - /* - * XXX Need to free derCerts? Or do they come out of arena? - * (Currently we never fill in derCerts, which is why the - * answer is not obvious. Once we do, add any necessary code - * here and remove this comment.) - */ - } - - /* - * We should actually never have a request without an arena, - * but check just in case. (If there isn't one, there is not - * much we can do about it...) - */ - PORT_Assert(request->arena != NULL); - if (request->arena != NULL) - PORT_FreeArena(request->arena, PR_FALSE); -} - - -/* - * RESPONSE SUPPORT FUNCTIONS (encode/create/decode/destroy): - */ - -/* - * Helper function for encoding or decoding a ResponderID -- based on the - * given type, return the associated template for that choice. - */ -static const SEC_ASN1Template * -ocsp_ResponderIDTemplateByType(ocspResponderIDType responderIDType) -{ - const SEC_ASN1Template *responderIDTemplate; - - switch (responderIDType) { - case ocspResponderID_byName: - responderIDTemplate = ocsp_ResponderIDByNameTemplate; - break; - case ocspResponderID_byKey: - responderIDTemplate = ocsp_ResponderIDByKeyTemplate; - break; - case ocspResponderID_other: - default: - PORT_Assert(responderIDType == ocspResponderID_other); - responderIDTemplate = ocsp_ResponderIDOtherTemplate; - break; - } - - return responderIDTemplate; -} - -/* - * Helper function for encoding or decoding a CertStatus -- based on the - * given type, return the associated template for that choice. - */ -static const SEC_ASN1Template * -ocsp_CertStatusTemplateByType(ocspCertStatusType certStatusType) -{ - const SEC_ASN1Template *certStatusTemplate; - - switch (certStatusType) { - case ocspCertStatus_good: - certStatusTemplate = ocsp_CertStatusGoodTemplate; - break; - case ocspCertStatus_revoked: - certStatusTemplate = ocsp_CertStatusRevokedTemplate; - break; - case ocspCertStatus_unknown: - certStatusTemplate = ocsp_CertStatusUnknownTemplate; - break; - case ocspCertStatus_other: - default: - PORT_Assert(certStatusType == ocspCertStatus_other); - certStatusTemplate = ocsp_CertStatusOtherTemplate; - break; - } - - return certStatusTemplate; -} - -/* - * Helper function for decoding a certStatus -- turn the actual DER tag - * into our local translation. - */ -static ocspCertStatusType -ocsp_CertStatusTypeByTag(int derTag) -{ - ocspCertStatusType certStatusType; - - switch (derTag) { - case 0: - certStatusType = ocspCertStatus_good; - break; - case 1: - certStatusType = ocspCertStatus_revoked; - break; - case 2: - certStatusType = ocspCertStatus_unknown; - break; - default: - certStatusType = ocspCertStatus_other; - break; - } - - return certStatusType; -} - -/* - * Helper function for decoding SingleResponses -- they each contain - * a status which is encoded as CHOICE, which needs to be decoded "by hand". - * - * Note -- on error, this routine does not release the memory it may - * have allocated; it expects its caller to do that. - */ -static SECStatus -ocsp_FinishDecodingSingleResponses(PRArenaPool *arena, - CERTOCSPSingleResponse **responses) -{ - ocspCertStatus *certStatus; - ocspCertStatusType certStatusType; - const SEC_ASN1Template *certStatusTemplate; - int derTag; - int i; - SECStatus rv = SECFailure; - - if (responses == NULL) /* nothing to do */ - return SECSuccess; - - for (i = 0; responses[i] != NULL; i++) { - /* - * The following assert points out internal errors (problems in - * the template definitions or in the ASN.1 decoder itself, etc.). - */ - PORT_Assert(responses[i]->derCertStatus.data != NULL); - - derTag = responses[i]->derCertStatus.data[0] & SEC_ASN1_TAGNUM_MASK; - certStatusType = ocsp_CertStatusTypeByTag(derTag); - certStatusTemplate = ocsp_CertStatusTemplateByType(certStatusType); - - certStatus = PORT_ArenaZAlloc(arena, sizeof(ocspCertStatus)); - if (certStatus == NULL) { - goto loser; - } - rv = SEC_ASN1DecodeItem(arena, certStatus, certStatusTemplate, - &responses[i]->derCertStatus); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - goto loser; - } - - certStatus->certStatusType = certStatusType; - responses[i]->certStatus = certStatus; - } - - return SECSuccess; - -loser: - return rv; -} - -/* - * Helper function for decoding a responderID -- turn the actual DER tag - * into our local translation. - */ -static ocspResponderIDType -ocsp_ResponderIDTypeByTag(int derTag) -{ - ocspResponderIDType responderIDType; - - switch (derTag) { - case 1: - responderIDType = ocspResponderID_byName; - break; - case 2: - responderIDType = ocspResponderID_byKey; - break; - default: - responderIDType = ocspResponderID_other; - break; - } - - return responderIDType; -} - -/* - * Decode "src" as a BasicOCSPResponse, returning the result. - */ -static ocspBasicOCSPResponse * -ocsp_DecodeBasicOCSPResponse(PRArenaPool *arena, SECItem *src) -{ - void *mark; - ocspBasicOCSPResponse *basicResponse; - ocspResponseData *responseData; - ocspResponderID *responderID; - ocspResponderIDType responderIDType; - const SEC_ASN1Template *responderIDTemplate; - int derTag; - SECStatus rv; - SECItem newsrc; - - mark = PORT_ArenaMark(arena); - - basicResponse = PORT_ArenaZAlloc(arena, sizeof(ocspBasicOCSPResponse)); - if (basicResponse == NULL) { - goto loser; - } - - /* copy the DER into the arena, since Quick DER returns data that points - into the DER input, which may get freed by the caller */ - rv = SECITEM_CopyItem(arena, &newsrc, src); - if ( rv != SECSuccess ) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(arena, basicResponse, - ocsp_BasicOCSPResponseTemplate, &newsrc); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - goto loser; - } - - responseData = basicResponse->tbsResponseData; - - /* - * The following asserts point out internal errors (problems in - * the template definitions or in the ASN.1 decoder itself, etc.). - */ - PORT_Assert(responseData != NULL); - PORT_Assert(responseData->derResponderID.data != NULL); - - /* - * XXX Because responderID is a CHOICE, which is not currently handled - * by our ASN.1 decoder, we have to decode it "by hand". - */ - derTag = responseData->derResponderID.data[0] & SEC_ASN1_TAGNUM_MASK; - responderIDType = ocsp_ResponderIDTypeByTag(derTag); - responderIDTemplate = ocsp_ResponderIDTemplateByType(responderIDType); - - responderID = PORT_ArenaZAlloc(arena, sizeof(ocspResponderID)); - if (responderID == NULL) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(arena, responderID, responderIDTemplate, - &responseData->derResponderID); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - goto loser; - } - - responderID->responderIDType = responderIDType; - responseData->responderID = responderID; - - /* - * XXX Each SingleResponse also contains a CHOICE, which has to be - * fixed up by hand. - */ - rv = ocsp_FinishDecodingSingleResponses(arena, responseData->responses); - if (rv != SECSuccess) { - goto loser; - } - - PORT_ArenaUnmark(arena, mark); - return basicResponse; - -loser: - PORT_ArenaRelease(arena, mark); - return NULL; -} - - -/* - * Decode the responseBytes based on the responseType found in "rbytes", - * leaving the resulting translated/decoded information in there as well. - */ -static SECStatus -ocsp_DecodeResponseBytes(PRArenaPool *arena, ocspResponseBytes *rbytes) -{ - PORT_Assert(rbytes != NULL); /* internal error, really */ - if (rbytes == NULL) - PORT_SetError(SEC_ERROR_INVALID_ARGS); /* XXX set better error? */ - - rbytes->responseTypeTag = SECOID_FindOIDTag(&rbytes->responseType); - switch (rbytes->responseTypeTag) { - case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: - { - ocspBasicOCSPResponse *basicResponse; - - basicResponse = ocsp_DecodeBasicOCSPResponse(arena, - &rbytes->response); - if (basicResponse == NULL) - return SECFailure; - - rbytes->decodedResponse.basic = basicResponse; - } - break; - - /* - * Add new/future response types here. - */ - - default: - PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE); - return SECFailure; - } - - return SECSuccess; -} - - -/* - * FUNCTION: CERT_DecodeOCSPResponse - * Decode a DER encoded OCSP Response. - * INPUTS: - * SECItem *src - * Pointer to a SECItem holding DER encoded OCSP Response. - * RETURN: - * Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response); - * the caller is responsible for destroying it. Or NULL if error (either - * response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE), - * it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE), - * or a low-level or internal error occurred). - */ -CERTOCSPResponse * -CERT_DecodeOCSPResponse(SECItem *src) -{ - PRArenaPool *arena = NULL; - CERTOCSPResponse *response = NULL; - SECStatus rv = SECFailure; - ocspResponseStatus sv; - SECItem newSrc; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto loser; - } - response = (CERTOCSPResponse *) PORT_ArenaZAlloc(arena, - sizeof(CERTOCSPResponse)); - if (response == NULL) { - goto loser; - } - response->arena = arena; - - /* copy the DER into the arena, since Quick DER returns data that points - into the DER input, which may get freed by the caller */ - rv = SECITEM_CopyItem(arena, &newSrc, src); - if ( rv != SECSuccess ) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(arena, response, ocsp_OCSPResponseTemplate, &newSrc); - if (rv != SECSuccess) { - if (PORT_GetError() == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - goto loser; - } - - sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus); - response->statusValue = sv; - if (sv != ocspResponse_successful) { - /* - * If the response status is anything but successful, then we - * are all done with decoding; the status is all there is. - */ - return response; - } - - /* - * A successful response contains much more information, still encoded. - * Now we need to decode that. - */ - rv = ocsp_DecodeResponseBytes(arena, response->responseBytes); - if (rv != SECSuccess) { - goto loser; - } - - return response; - -loser: - if (arena != NULL) { - PORT_FreeArena(arena, PR_FALSE); - } - return NULL; -} - -/* - * The way an OCSPResponse is defined, there are many levels to descend - * before getting to the actual response information. And along the way - * we need to check that the response *type* is recognizable, which for - * now means that it is a BasicOCSPResponse, because that is the only - * type currently defined. Rather than force all routines to perform - * a bunch of sanity checking every time they want to work on a response, - * this function isolates that and gives back the interesting part. - * Note that no copying is done, this just returns a pointer into the - * substructure of the response which is passed in. - * - * XXX This routine only works when a valid response structure is passed - * into it; this is checked with many assertions. Assuming the response - * was creating by decoding, it wouldn't make it this far without being - * okay. That is a sufficient assumption since the entire OCSP interface - * is only used internally. When this interface is officially exported, - * each assertion below will need to be followed-up with setting an error - * and returning (null). - */ -static ocspResponseData * -ocsp_GetResponseData(CERTOCSPResponse *response) -{ - ocspBasicOCSPResponse *basic; - ocspResponseData *responseData; - - PORT_Assert(response != NULL); - - PORT_Assert(response->responseBytes != NULL); - - PORT_Assert(response->responseBytes->responseTypeTag - == SEC_OID_PKIX_OCSP_BASIC_RESPONSE); - - basic = response->responseBytes->decodedResponse.basic; - PORT_Assert(basic != NULL); - - responseData = basic->tbsResponseData; - PORT_Assert(responseData != NULL); - - return responseData; -} - -/* - * Much like the routine above, except it returns the response signature. - * Again, no copy is done. - */ -static ocspSignature * -ocsp_GetResponseSignature(CERTOCSPResponse *response) -{ - ocspBasicOCSPResponse *basic; - - PORT_Assert(response != NULL); - if (NULL == response->responseBytes) { - return NULL; - } - PORT_Assert(response->responseBytes != NULL); - PORT_Assert(response->responseBytes->responseTypeTag - == SEC_OID_PKIX_OCSP_BASIC_RESPONSE); - - basic = response->responseBytes->decodedResponse.basic; - PORT_Assert(basic != NULL); - - return &(basic->responseSignature); -} - - -/* - * FUNCTION: CERT_DestroyOCSPResponse - * Frees an OCSP Response structure. - * INPUTS: - * CERTOCSPResponse *request - * Pointer to CERTOCSPResponse to be freed. - * RETURN: - * No return value; no errors. - */ -void -CERT_DestroyOCSPResponse(CERTOCSPResponse *response) -{ - if (response != NULL) { - ocspSignature *signature = ocsp_GetResponseSignature(response); - if (signature && signature->cert != NULL) - CERT_DestroyCertificate(signature->cert); - - /* - * We should actually never have a response without an arena, - * but check just in case. (If there isn't one, there is not - * much we can do about it...) - */ - PORT_Assert(response->arena != NULL); - if (response->arena != NULL) { - PORT_FreeArena(response->arena, PR_FALSE); - } - } -} - - -/* - * OVERALL OCSP CLIENT SUPPORT (make and send a request, verify a response): - */ - - -/* - * Pick apart a URL, saving the important things in the passed-in pointers. - * - * We expect to find "http://<hostname>[:<port>]/[path]", though we will - * tolerate that final slash character missing, as well as beginning and - * trailing whitespace, and any-case-characters for "http". All of that - * tolerance is what complicates this routine. What we want is just to - * pick out the hostname, the port, and the path. - * - * On a successful return, the caller will need to free the output pieces - * of hostname and path, which are copies of the values found in the url. - */ -static SECStatus -ocsp_ParseURL(char *url, char **pHostname, PRUint16 *pPort, char **pPath) -{ - unsigned short port = 80; /* default, in case not in url */ - char *hostname = NULL; - char *path = NULL; - char *save; - char c; - int len; - - if (url == NULL) - goto loser; - - /* - * Skip beginning whitespace. - */ - c = *url; - while ((c == ' ' || c == '\t') && c != '\0') { - url++; - c = *url; - } - if (c == '\0') - goto loser; - - /* - * Confirm, then skip, protocol. (Since we only know how to do http, - * that is all we will accept). - */ - if (PORT_Strncasecmp(url, "http://", 7) != 0) - goto loser; - url += 7; - - /* - * Whatever comes next is the hostname (or host IP address). We just - * save it aside and then search for its end so we can determine its - * length and copy it. - * - * XXX Note that because we treat a ':' as a terminator character - * (and below, we expect that to mean there is a port specification - * immediately following), we will not handle IPv6 addresses. That is - * apparently an acceptable limitation, for the time being. Some day, - * when there is a clear way to specify a URL with an IPv6 address that - * can be parsed unambiguously, this code should be made to do that. - */ - save = url; - c = *url; - while (c != '/' && c != ':' && c != '\0' && c != ' ' && c != '\t') { - url++; - c = *url; - } - len = url - save; - hostname = PORT_Alloc(len + 1); - if (hostname == NULL) - goto loser; - PORT_Memcpy(hostname, save, len); - hostname[len] = '\0'; - - /* - * Now we figure out if there was a port specified or not. - * If so, we need to parse it (as a number) and skip it. - */ - if (c == ':') { - url++; - port = (unsigned short) PORT_Atoi(url); - c = *url; - while (c != '/' && c != '\0' && c != ' ' && c != '\t') { - if (c < '0' || c > '9') - goto loser; - url++; - c = *url; - } - } - - /* - * Last thing to find is a path. There *should* be a slash, - * if nothing else -- but if there is not we provide one. - */ - if (c == '/') { - save = url; - while (c != '\0' && c != ' ' && c != '\t') { - url++; - c = *url; - } - len = url - save; - path = PORT_Alloc(len + 1); - if (path == NULL) - goto loser; - PORT_Memcpy(path, save, len); - path[len] = '\0'; - } else { - path = PORT_Strdup("/"); - if (path == NULL) - goto loser; - } - - *pHostname = hostname; - *pPort = port; - *pPath = path; - return SECSuccess; - -loser: - if (hostname != NULL) - PORT_Free(hostname); - PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); - return SECFailure; -} - -/* - * Open a socket to the specified host on the specified port, and return it. - * The host is either a hostname or an IP address. - */ -static PRFileDesc * -ocsp_ConnectToHost(const char *host, PRUint16 port) -{ - PRFileDesc *sock = NULL; - PRIntervalTime timeout; - PRNetAddr addr; - char *netdbbuf = NULL; - - sock = PR_NewTCPSocket(); - if (sock == NULL) - goto loser; - - /* XXX Some day need a way to set (and get?) the following value */ - timeout = PR_SecondsToInterval(30); - - /* - * If the following converts an IP address string in "dot notation" - * into a PRNetAddr. If it fails, we assume that is because we do not - * have such an address, but instead a host *name*. In that case we - * then lookup the host by name. Using the NSPR function this way - * means we do not have to have our own logic for distinguishing a - * valid numerical IP address from a hostname. - */ - if (PR_StringToNetAddr(host, &addr) != PR_SUCCESS) { - PRIntn hostIndex; - PRHostEnt hostEntry; - - netdbbuf = PORT_Alloc(PR_NETDB_BUF_SIZE); - if (netdbbuf == NULL) - goto loser; - - if (PR_GetHostByName(host, netdbbuf, PR_NETDB_BUF_SIZE, - &hostEntry) != PR_SUCCESS) - goto loser; - - hostIndex = 0; - do { - hostIndex = PR_EnumerateHostEnt(hostIndex, &hostEntry, port, &addr); - if (hostIndex <= 0) - goto loser; - } while (PR_Connect(sock, &addr, timeout) != PR_SUCCESS); - - PORT_Free(netdbbuf); - } else { - /* - * First put the port into the address, then connect. - */ - if (PR_InitializeNetAddr(PR_IpAddrNull, port, &addr) != PR_SUCCESS) - goto loser; - if (PR_Connect(sock, &addr, timeout) != PR_SUCCESS) - goto loser; - } - - return sock; - -loser: - if (sock != NULL) - PR_Close(sock); - if (netdbbuf != NULL) - PORT_Free(netdbbuf); - return NULL; -} - -/* - * Sends an encoded OCSP request to the server identified by "location", - * and returns the socket on which it was sent (so can listen for the reply). - * "location" is expected to be a valid URL -- an error parsing it produces - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION. Other errors are likely problems - * connecting to it, or writing to it, or allocating memory, and the low-level - * errors appropriate to the problem will be set. - */ -static PRFileDesc * -ocsp_SendEncodedRequest(char *location, SECItem *encodedRequest) -{ - char *hostname = NULL; - char *path = NULL; - PRUint16 port; - SECStatus rv; - PRFileDesc *sock = NULL; - PRFileDesc *returnSock = NULL; - char *header = NULL; - - /* - * Take apart the location, getting the hostname, port, and path. - */ - rv = ocsp_ParseURL(location, &hostname, &port, &path); - if (rv != SECSuccess) - goto loser; - - PORT_Assert(hostname != NULL); - PORT_Assert(path != NULL); - - sock = ocsp_ConnectToHost(hostname, port); - if (sock == NULL) - goto loser; - - header = PR_smprintf("POST %s HTTP/1.0\r\n" - "Host: %s:%d\r\n" - "Content-Type: application/ocsp-request\r\n" - "Content-Length: %u\r\n\r\n", - path, hostname, port, encodedRequest->len); - if (header == NULL) - goto loser; - - /* - * The NSPR documentation promises that if it can, it will write the full - * amount; this will not return a partial value expecting us to loop. - */ - if (PR_Write(sock, header, (PRInt32) PORT_Strlen(header)) < 0) - goto loser; - - if (PR_Write(sock, encodedRequest->data, - (PRInt32) encodedRequest->len) < 0) - goto loser; - - returnSock = sock; - sock = NULL; - -loser: - if (header != NULL) - PORT_Free(header); - if (sock != NULL) - PR_Close(sock); - if (path != NULL) - PORT_Free(path); - if (hostname != NULL) - PORT_Free(hostname); - - return returnSock; -} - -/* - * Read from "fd" into "buf" -- expect/attempt to read a given number of bytes - * Obviously, stop if hit end-of-stream. Timeout is passed in. - */ - -static int -ocsp_read(PRFileDesc *fd, char *buf, int toread, PRIntervalTime timeout) -{ - int total = 0; - - while (total < toread) - { - PRInt32 got; - - got = PR_Recv(fd, buf + total, (PRInt32) (toread - total), 0, timeout); - if (got < 0) - { - if (0 == total) - { - total = -1; /* report the error if we didn't read anything yet */ - } - break; - } - else - if (got == 0) - { /* EOS */ - break; - } - - total += got; - } - - return total; -} - -#define OCSP_BUFSIZE 1024 - -#define AbortHttpDecode(error) \ -{ \ - if (inBuffer) \ - PORT_Free(inBuffer); \ - PORT_SetError(error); \ - return NULL; \ -} - - -/* - * Reads on the given socket and returns an encoded response when received. - * Properly formatted HTTP/1.0 response headers are expected to be read - * from the socket, preceding a binary-encoded OCSP response. Problems - * with parsing cause the error SEC_ERROR_OCSP_BAD_HTTP_RESPONSE to be - * set; any other problems are likely low-level i/o or memory allocation - * errors. - */ -static SECItem * -ocsp_GetEncodedResponse(PRArenaPool *arena, PRFileDesc *sock) -{ - /* first read HTTP status line and headers */ - - char* inBuffer = NULL; - PRInt32 offset = 0; - PRInt32 inBufsize = 0; - const PRInt32 bufSizeIncrement = OCSP_BUFSIZE; /* 1 KB at a time */ - const PRInt32 maxBufSize = 8 * bufSizeIncrement ; /* 8 KB max */ - const char* CRLF = "\r\n"; - const PRInt32 CRLFlen = strlen(CRLF); - const char* headerEndMark = "\r\n\r\n"; - const PRInt32 markLen = strlen(headerEndMark); - const PRIntervalTime ocsptimeout = - PR_SecondsToInterval(30); /* hardcoded to 30s for now */ - char* headerEnd = NULL; - PRBool EOS = PR_FALSE; - const char* httpprotocol = "HTTP/"; - const PRInt32 httplen = strlen(httpprotocol); - const char* httpcode = NULL; - const char* contenttype = NULL; - PRInt32 contentlength = 0; - PRInt32 bytesRead = 0; - char* statusLineEnd = NULL; - char* space = NULL; - char* nextHeader = NULL; - SECItem* result = NULL; - - /* read up to at least the end of the HTTP headers */ - do - { - inBufsize += bufSizeIncrement; - inBuffer = PORT_Realloc(inBuffer, inBufsize+1); - if (NULL == inBuffer) - { - AbortHttpDecode(SEC_ERROR_NO_MEMORY); - } - bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement, - ocsptimeout); - if (bytesRead > 0) - { - PRInt32 searchOffset = (offset - markLen) >0 ? offset-markLen : 0; - offset += bytesRead; - *(inBuffer + offset) = '\0'; /* NULL termination */ - headerEnd = strstr((const char*)inBuffer + searchOffset, headerEndMark); - if (bytesRead < bufSizeIncrement) - { - /* we read less data than requested, therefore we are at - EOS or there was a read error */ - EOS = PR_TRUE; - } - } - else - { - /* recv error or EOS */ - EOS = PR_TRUE; - } - } while ( (!headerEnd) && (PR_FALSE == EOS) && - (inBufsize < maxBufSize) ); - - if (!headerEnd) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - /* parse the HTTP status line */ - statusLineEnd = strstr((const char*)inBuffer, CRLF); - if (!statusLineEnd) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - *statusLineEnd = '\0'; - - /* check for HTTP/ response */ - space = strchr((const char*)inBuffer, ' '); - if (!space || PORT_Strncasecmp((const char*)inBuffer, httpprotocol, httplen) != 0 ) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - /* check the HTTP status code of 200 */ - httpcode = space +1; - space = strchr(httpcode, ' '); - if (!space) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - *space = 0; - if (0 != strcmp(httpcode, "200")) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - /* parse the HTTP headers in the buffer . We only care about - content-type and content-length - */ - - nextHeader = statusLineEnd + CRLFlen; - *headerEnd = '\0'; /* terminate */ - do - { - char* thisHeaderEnd = NULL; - char* value = NULL; - char* colon = strchr(nextHeader, ':'); - - if (!colon) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - *colon = '\0'; - value = colon + 1; - - /* jpierre - note : the following code will only handle the basic form - of HTTP/1.0 response headers, of the form "name: value" . Headers - split among multiple lines are not supported. This is not common - and should not be an issue, but it could become one in the - future */ - - if (*value != ' ') - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - value++; - thisHeaderEnd = strstr(value, CRLF); - if (thisHeaderEnd ) - { - *thisHeaderEnd = '\0'; - } - - if (0 == PORT_Strcasecmp(nextHeader, "content-type")) - { - contenttype = value; - } - else - if (0 == PORT_Strcasecmp(nextHeader, "content-length")) - { - contentlength = atoi(value); - } - - if (thisHeaderEnd ) - { - nextHeader = thisHeaderEnd + CRLFlen; - } - else - { - nextHeader = NULL; - } - - } while (nextHeader && (nextHeader < (headerEnd + CRLFlen) ) ); - - /* check content-type */ - if (!contenttype || - (0 != PORT_Strcasecmp(contenttype, "application/ocsp-response")) ) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - /* read the body of the OCSP response */ - offset = offset - (PRInt32) (headerEnd - (const char*)inBuffer) - markLen; - if (offset) - { - /* move all data to the beginning of the buffer */ - PORT_Memmove(inBuffer, headerEnd + markLen, offset); - } - - /* resize buffer to only what's needed to hold the current response */ - inBufsize = (1 + (offset-1) / bufSizeIncrement ) * bufSizeIncrement ; - - while ( (PR_FALSE == EOS) && - ( (contentlength == 0) || (offset < contentlength) ) && - (inBufsize < maxBufSize) - ) - { - /* we still need to receive more body data */ - inBufsize += bufSizeIncrement; - inBuffer = PORT_Realloc(inBuffer, inBufsize+1); - if (NULL == inBuffer) - { - AbortHttpDecode(SEC_ERROR_NO_MEMORY); - } - bytesRead = ocsp_read(sock, inBuffer + offset, bufSizeIncrement, - ocsptimeout); - if (bytesRead > 0) - { - offset += bytesRead; - if (bytesRead < bufSizeIncrement) - { - /* we read less data than requested, therefore we are at - EOS or there was a read error */ - EOS = PR_TRUE; - } - } - else - { - /* recv error or EOS */ - EOS = PR_TRUE; - } - } - - if (0 == offset) - { - AbortHttpDecode(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - } - - /* - * Now allocate the item to hold the data. - */ - result = SECITEM_AllocItem(arena, NULL, offset); - if (NULL == result) - { - AbortHttpDecode(SEC_ERROR_NO_MEMORY); - } - - /* - * And copy the data left in the buffer. - */ - PORT_Memcpy(result->data, inBuffer, offset); - - /* and free the temporary buffer */ - PORT_Free(inBuffer); - return result; -} - -/* - * Limit the size of http responses we are willing to accept. - */ -#define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024 - -static SECItem * -fetchOcspHttpClientV1(PRArenaPool *arena, - const SEC_HttpClientFcnV1 *hcv1, - char *location, - SECItem *encodedRequest) -{ - char *hostname = NULL; - char *path = NULL; - PRUint16 port; - SECItem *encodedResponse = NULL; - SEC_HTTP_SERVER_SESSION pServerSession = NULL; - SEC_HTTP_REQUEST_SESSION pRequestSession = NULL; - PRUint16 myHttpResponseCode; - const char *myHttpResponseData; - PRUint32 myHttpResponseDataLen; - - if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) { - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); - goto loser; - } - - PORT_Assert(hostname != NULL); - PORT_Assert(path != NULL); - - if ((*hcv1->createSessionFcn)( - hostname, - port, - &pServerSession) != SECSuccess) { - PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); - goto loser; - } - - /* We use a non-zero timeout, which means: - - the client will use blocking I/O - - TryFcn will not return WOULD_BLOCK nor a poll descriptor - - it's sufficient to call TryFcn once - */ - - if ((*hcv1->createFcn)( - pServerSession, - "http", - path, - "POST", - PR_TicksPerSecond() * 60, - &pRequestSession) != SECSuccess) { - PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); - goto loser; - } - - if ((*hcv1->setPostDataFcn)( - pRequestSession, - (char*)encodedRequest->data, - encodedRequest->len, - "application/ocsp-request") != SECSuccess) { - PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); - goto loser; - } - - /* we don't want result objects larger than this: */ - myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN; - - if ((*hcv1->trySendAndReceiveFcn)( - pRequestSession, - NULL, - &myHttpResponseCode, - NULL, - NULL, - &myHttpResponseData, - &myHttpResponseDataLen) != SECSuccess) { - PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); - goto loser; - } - - if (myHttpResponseCode != 200) { - PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE); - goto loser; - } - - encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen); - - if (!encodedResponse) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - goto loser; - } - - PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen); - -loser: - if (pRequestSession != NULL) - (*hcv1->freeFcn)(pRequestSession); - if (pServerSession != NULL) - (*hcv1->freeSessionFcn)(pServerSession); - if (path != NULL) - PORT_Free(path); - if (hostname != NULL) - PORT_Free(hostname); - - return encodedResponse; -} - -/* - * FUNCTION: CERT_GetEncodedOCSPResponse - * Creates and sends a request to an OCSP responder, then reads and - * returns the (encoded) response. - * INPUTS: - * PRArenaPool *arena - * Pointer to arena from which return value will be allocated. - * If NULL, result will be allocated from the heap (and thus should - * be freed via SECITEM_FreeItem). - * CERTCertList *certList - * A list of certs for which status will be requested. - * Note that all of these certificates should have the same issuer, - * or it's expected the response will be signed by a trusted responder. - * If the certs need to be broken up into multiple requests, that - * must be handled by the caller (and thus by having multiple calls - * to this routine), who knows about where the request(s) are being - * sent and whether there are any trusted responders in place. - * char *location - * The location of the OCSP responder (a URL). - * int64 time - * Indicates the time for which the certificate status is to be - * determined -- this may be used in the search for the cert's issuer - * but has no other bearing on the operation. - * PRBool addServiceLocator - * If true, the Service Locator extension should be added to the - * single request(s) for each cert. - * CERTCertificate *signerCert - * If non-NULL, means sign the request using this cert. Otherwise, - * do not sign. - * void *pwArg - * Pointer to argument for password prompting, if needed. (Definitely - * not needed if not signing.) - * OUTPUTS: - * CERTOCSPRequest **pRequest - * Pointer in which to store the OCSP request created for the given - * list of certificates. It is only filled in if the entire operation - * is successful and the pointer is not null -- and in that case the - * caller is then reponsible for destroying it. - * RETURN: - * Returns a pointer to the SECItem holding the response. - * On error, returns null with error set describing the reason: - * SEC_ERROR_UNKNOWN_ISSUER - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION - * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE - * Other errors are low-level problems (no memory, bad database, etc.). - */ -SECItem * -CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList, - char *location, int64 time, - PRBool addServiceLocator, - CERTCertificate *signerCert, void *pwArg, - CERTOCSPRequest **pRequest) -{ - CERTOCSPRequest *request = NULL; - SECItem *encodedRequest = NULL; - SECItem *encodedResponse = NULL; - PRFileDesc *sock = NULL; - SECStatus rv; - const SEC_HttpClientFcn *registeredHttpClient = NULL; - - request = CERT_CreateOCSPRequest(certList, time, addServiceLocator, - signerCert); - if (request == NULL) - goto loser; - - rv = CERT_AddOCSPAcceptableResponses(request, - SEC_OID_PKIX_OCSP_BASIC_RESPONSE); - if (rv != SECSuccess) - goto loser; - - encodedRequest = CERT_EncodeOCSPRequest(NULL, request, pwArg); - if (encodedRequest == NULL) - goto loser; - - registeredHttpClient = GetRegisteredHttpClient(); - - if (registeredHttpClient - && - registeredHttpClient->version == 1) { - encodedResponse = fetchOcspHttpClientV1( - arena, - ®isteredHttpClient->fcnTable.ftable1, - location, - encodedRequest); - } - else { - /* use internal http client */ - - sock = ocsp_SendEncodedRequest(location, encodedRequest); - if (sock == NULL) - goto loser; - - encodedResponse = ocsp_GetEncodedResponse(arena, sock); - } - - if (encodedResponse != NULL && pRequest != NULL) { - *pRequest = request; - request = NULL; /* avoid destroying below */ - } - -loser: - if (request != NULL) - CERT_DestroyOCSPRequest(request); - if (encodedRequest != NULL) - SECITEM_FreeItem(encodedRequest, PR_TRUE); - if (sock != NULL) - PR_Close(sock); - - return encodedResponse; -} - - -/* Checks a certificate for the key usage extension of OCSP signer. */ -static PRBool -ocsp_CertIsOCSPSigner(CERTCertificate *cert) -{ - SECStatus rv; - SECItem extItem; - SECItem **oids; - SECItem *oid; - SECOidTag oidTag; - PRBool retval; - CERTOidSequence *oidSeq = NULL; - - - extItem.data = NULL; - rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem); - if ( rv != SECSuccess ) { - goto loser; - } - - oidSeq = CERT_DecodeOidSequence(&extItem); - if ( oidSeq == NULL ) { - goto loser; - } - - oids = oidSeq->oids; - while ( *oids != NULL ) { - oid = *oids; - - oidTag = SECOID_FindOIDTag(oid); - - if ( oidTag == SEC_OID_OCSP_RESPONDER ) { - goto success; - } - - oids++; - } - -loser: - retval = PR_FALSE; - PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); - goto done; -success: - retval = PR_TRUE; -done: - if ( extItem.data != NULL ) { - PORT_Free(extItem.data); - } - if ( oidSeq != NULL ) { - CERT_DestroyOidSequence(oidSeq); - } - - return(retval); -} - - -#ifdef LATER /* - * XXX This function is not currently used, but will - * be needed later when we do revocation checking of - * the responder certificate. Of course, it may need - * revising then, if the cert extension interface has - * changed. (Hopefully it will!) - */ - -/* Checks a certificate to see if it has the OCSP no check extension. */ -static PRBool -ocsp_CertHasNoCheckExtension(CERTCertificate *cert) -{ - SECStatus rv; - - rv = CERT_FindCertExtension(cert, SEC_OID_PKIX_OCSP_NO_CHECK, - NULL); - if (rv == SECSuccess) { - return PR_TRUE; - } - return PR_FALSE; -} -#endif /* LATER */ - -static PRBool -ocsp_matchcert(SECItem *certIndex,CERTCertificate *testCert) -{ - SECItem item; - unsigned char buf[HASH_LENGTH_MAX]; - - item.data = buf; - item.len = SHA1_LENGTH; - - if (CERT_SPKDigestValueForCert(NULL,testCert,SEC_OID_SHA1, &item) == NULL) { - return PR_FALSE; - } - if (SECITEM_ItemsAreEqual(certIndex,&item)) { - return PR_TRUE; - } - if (CERT_SPKDigestValueForCert(NULL,testCert,SEC_OID_MD5, &item) == NULL) { - return PR_FALSE; - } - if (SECITEM_ItemsAreEqual(certIndex,&item)) { - return PR_TRUE; - } - if (CERT_SPKDigestValueForCert(NULL,testCert,SEC_OID_MD2, &item) == NULL) { - return PR_FALSE; - } - if (SECITEM_ItemsAreEqual(certIndex,&item)) { - return PR_TRUE; - } - - return PR_FALSE; -} - -static CERTCertificate * -ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle,CERTOCSPCertID *certID); - -/* - * Check the signature on some OCSP data. This is a helper function that - * can be used to check either a request or a response. The result is - * saved in the signature structure itself for future reference (to avoid - * repeating the expensive verification operation), as well as returned. - * In addition to checking the signature, the certificate (and its chain) - * are also checked for validity (at the specified time) and usage. - * - * The type of cert lookup to be performed is specified by "lookupByName": - * if true, then "certIndex" is actually a CERTName; otherwise it is a - * SECItem which contains a key hash. - * - * If the signature verifies okay, and the argument "pSignerCert" is not - * null, that parameter will be filled-in with a pointer to the signer's - * certificate. The caller is then responsible for destroying the cert. - * - * A return of SECSuccess means the verification succeeded. If not, - * an error will be set with the reason. Most likely are: - * SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found - * SEC_ERROR_BAD_SIGNATURE - the signature did not verify - * Other errors are any of the many possible failures in cert verification - * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when - * verifying the signer's cert, or low-level problems (no memory, etc.) - */ -static SECStatus -ocsp_CheckSignature(ocspSignature *signature, void *tbs, - const SEC_ASN1Template *encodeTemplate, - CERTCertDBHandle *handle, SECCertUsage certUsage, - int64 checkTime, PRBool lookupByName, void *certIndex, - void *pwArg, CERTCertificate **pSignerCert, - CERTCertificate *issuer) -{ - SECItem rawSignature; - SECItem *encodedTBS = NULL; - CERTCertificate *responder = NULL; - CERTCertificate *signerCert = NULL; - SECKEYPublicKey *signerKey = NULL; - CERTCertificate **certs = NULL; - SECStatus rv = SECFailure; - int certCount; - int i; - - /* - * If this signature has already gone through verification, just - * return the cached result. - */ - if (signature->wasChecked) { - if (signature->status == SECSuccess) { - if (pSignerCert != NULL) - *pSignerCert = CERT_DupCertificate(signature->cert); - } else { - PORT_SetError(signature->failureReason); - } - return signature->status; - } - - /* - * If the signature contains some certificates as well, temporarily - * import them in case they are needed for verification. - * - * Note that the result of this is that each cert in "certs" needs - * to be destroyed. - */ - certCount = 0; - if (signature->derCerts != NULL) { - for (; signature->derCerts[certCount] != NULL; certCount++) { - /* just counting */ - /*IMPORT CERT TO SPKI TABLE */ - } - } - rv = CERT_ImportCerts(handle, certUsage, certCount, - signature->derCerts, &certs, - PR_FALSE, PR_FALSE, NULL); - if (rv != SECSuccess) - goto finish; - - /* - * Now look up the certificate that did the signing. - * The signer can be specified either by name or by key hash. - */ - if (lookupByName) { - SECItem *encodedName; - - encodedName = SEC_ASN1EncodeItem(NULL, NULL, certIndex, - CERT_NameTemplate); - if (encodedName == NULL) - goto finish; - - signerCert = CERT_FindCertByName(handle, encodedName); - SECITEM_FreeItem(encodedName, PR_TRUE); - } else { - /* - * The signer is either 1) a known issuer CA we passed in, - * 2) the default OCSP responder, or 3) an intermediate CA - * passed in the cert list to use. Figure out which it is. - */ - responder = ocsp_CertGetDefaultResponder(handle,NULL); - if (responder && ocsp_matchcert(certIndex,responder)) { - signerCert = CERT_DupCertificate(responder); - } else if (issuer && ocsp_matchcert(certIndex,issuer)) { - signerCert = CERT_DupCertificate(issuer); - } - for (i=0; (signerCert == NULL) && (i < certCount); i++) { - if (ocsp_matchcert(certIndex,certs[i])) { - signerCert = CERT_DupCertificate(certs[i]); - } - } - } - - if (signerCert == NULL) { - rv = SECFailure; - if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) { - /* Make the error a little more specific. */ - PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); - } - goto finish; - } - - /* - * We could mark this true at the top of this function, or always - * below at "finish", but if the problem was just that we could not - * find the signer's cert, leave that as if the signature hasn't - * been checked in case a subsequent call might have better luck. - */ - signature->wasChecked = PR_TRUE; - - /* - * Just because we have a cert does not mean it is any good; check - * it for validity, trust and usage. - */ - rv = CERT_VerifyCert(handle, signerCert, PR_TRUE, certUsage, checkTime, - pwArg, NULL); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); - goto finish; - } - - /* - * Now get the public key from the signer's certificate; we need - * it to perform the verification. - */ - signerKey = CERT_ExtractPublicKey(signerCert); - if (signerKey == NULL) - goto finish; - - /* - * Prepare the data to be verified; it needs to be DER encoded first. - */ - encodedTBS = SEC_ASN1EncodeItem(NULL, NULL, tbs, encodeTemplate); - if (encodedTBS == NULL) - goto finish; - - /* - * We copy the signature data *pointer* and length, so that we can - * modify the length without damaging the original copy. This is a - * simple copy, not a dup, so no destroy/free is necessary. - */ - rawSignature = signature->signature; - /* - * The raw signature is a bit string, but we need to represent its - * length in bytes, because that is what the verify function expects. - */ - DER_ConvertBitString(&rawSignature); - - rv = VFY_VerifyDataWithAlgorithmID(encodedTBS->data, encodedTBS->len, - signerKey, &rawSignature, - &signature->signatureAlgorithm, NULL, pwArg); - -finish: - if (signature->wasChecked) - signature->status = rv; - - if (rv != SECSuccess) { - signature->failureReason = PORT_GetError(); - if (signerCert != NULL) - CERT_DestroyCertificate(signerCert); - } else { - /* - * Save signer's certificate in signature. - */ - signature->cert = signerCert; - if (pSignerCert != NULL) { - /* - * Pass pointer to signer's certificate back to our caller, - * who is also now responsible for destroying it. - */ - *pSignerCert = CERT_DupCertificate(signerCert); - } - } - - if (encodedTBS != NULL) - SECITEM_FreeItem(encodedTBS, PR_TRUE); - - if (signerKey != NULL) - SECKEY_DestroyPublicKey(signerKey); - - if (certs != NULL) - CERT_DestroyCertArray(certs, certCount); - /* Free CERTS from SPKDigest Table */ - - return rv; -} - - -/* - * FUNCTION: CERT_VerifyOCSPResponseSignature - * Check the signature on an OCSP Response. Will also perform a - * verification of the signer's certificate. Note, however, that a - * successful verification does not make any statement about the - * signer's *authority* to provide status for the certificate(s), - * that must be checked individually for each certificate. - * INPUTS: - * CERTOCSPResponse *response - * Pointer to response structure with signature to be checked. - * CERTCertDBHandle *handle - * Pointer to CERTCertDBHandle for certificate DB to use for verification. - * void *pwArg - * Pointer to argument for password prompting, if needed. - * OUTPUTS: - * CERTCertificate **pSignerCert - * Pointer in which to store signer's certificate; only filled-in if - * non-null. - * RETURN: - * Returns SECSuccess when signature is valid, anything else means invalid. - * Possible errors set: - * SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID - * SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time - * SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found - * SEC_ERROR_BAD_SIGNATURE - the signature did not verify - * Other errors are any of the many possible failures in cert verification - * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when - * verifying the signer's cert, or low-level problems (no memory, etc.) - */ -SECStatus -CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response, - CERTCertDBHandle *handle, void *pwArg, - CERTCertificate **pSignerCert, - CERTCertificate *issuer) -{ - ocspResponseData *tbsData; /* this is what is signed */ - PRBool byName; - void *certIndex; - int64 producedAt; - SECStatus rv; - - tbsData = ocsp_GetResponseData(response); - - PORT_Assert(tbsData->responderID != NULL); - switch (tbsData->responderID->responderIDType) { - case ocspResponderID_byName: - byName = PR_TRUE; - certIndex = &tbsData->responderID->responderIDValue.name; - break; - case ocspResponderID_byKey: - byName = PR_FALSE; - certIndex = &tbsData->responderID->responderIDValue.keyHash; - break; - case ocspResponderID_other: - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - return SECFailure; - } - - /* - * ocsp_CheckSignature will also verify the signer certificate; we - * need to tell it *when* that certificate must be valid -- for our - * purposes we expect it to be valid when the response was signed. - * The value of "producedAt" is the signing time. - */ - rv = DER_GeneralizedTimeToTime(&producedAt, &tbsData->producedAt); - if (rv != SECSuccess) - return rv; - - return ocsp_CheckSignature(ocsp_GetResponseSignature(response), - tbsData, ocsp_ResponseDataTemplate, - handle, certUsageStatusResponder, producedAt, - byName, certIndex, pwArg, pSignerCert, issuer); -} - -/* - * See if the request's certID and the single response's certID match. - * This can be easy or difficult, depending on whether the same hash - * algorithm was used. - */ -static PRBool -ocsp_CertIDsMatch(CERTCertDBHandle *handle, - CERTOCSPCertID *requestCertID, - CERTOCSPCertID *responseCertID) -{ - PRBool match = PR_FALSE; - SECOidTag hashAlg; - SECItem *keyHash = NULL; - SECItem *nameHash = NULL; - - /* - * In order to match, they must have the same issuer and the same - * serial number. - * - * We just compare the easier things first. - */ - if (SECITEM_CompareItem(&requestCertID->serialNumber, - &responseCertID->serialNumber) != SECEqual) { - goto done; - } - - /* - * Make sure the "parameters" are not too bogus. Since we encoded - * requestCertID->hashAlgorithm, we don't need to check it. - */ - if (responseCertID->hashAlgorithm.parameters.len > 2) { - goto done; - } - if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm, - &responseCertID->hashAlgorithm.algorithm) == SECEqual) { - /* - * If the hash algorithms match then we can do a simple compare - * of the hash values themselves. - */ - if ((SECITEM_CompareItem(&requestCertID->issuerNameHash, - &responseCertID->issuerNameHash) == SECEqual) - && (SECITEM_CompareItem(&requestCertID->issuerKeyHash, - &responseCertID->issuerKeyHash) == SECEqual)) { - match = PR_TRUE; - } - goto done; - } - - hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm); - switch (hashAlg) { - case SEC_OID_SHA1: - keyHash = &requestCertID->issuerSHA1KeyHash; - nameHash = &requestCertID->issuerSHA1NameHash; - break; - case SEC_OID_MD5: - keyHash = &requestCertID->issuerMD5KeyHash; - nameHash = &requestCertID->issuerMD5NameHash; - break; - case SEC_OID_MD2: - keyHash = &requestCertID->issuerMD2KeyHash; - nameHash = &requestCertID->issuerMD2NameHash; - break; - } - - if ((keyHash != NULL) - && (SECITEM_CompareItem(nameHash, - &responseCertID->issuerNameHash) == SECEqual) - && (SECITEM_CompareItem(keyHash, - &responseCertID->issuerKeyHash) == SECEqual)) { - match = PR_TRUE; - } - -done: - return match; -} - -/* - * Find the single response for the cert specified by certID. - * No copying is done; this just returns a pointer to the appropriate - * response within responses, if it is found (and null otherwise). - * This is fine, of course, since this function is internal-use only. - */ -static CERTOCSPSingleResponse * -ocsp_GetSingleResponseForCertID(CERTOCSPSingleResponse **responses, - CERTCertDBHandle *handle, - CERTOCSPCertID *certID) -{ - CERTOCSPSingleResponse *single; - int i; - - if (responses == NULL) - return NULL; - - for (i = 0; responses[i] != NULL; i++) { - single = responses[i]; - if (ocsp_CertIDsMatch(handle, certID, single->certID) == PR_TRUE) { - return single; - } - } - - /* - * The OCSP server should have included a response even if it knew - * nothing about the certificate in question. Since it did not, - * this will make it look as if it had. - * - * XXX Should we make this a separate error to notice the server's - * bad behavior? - */ - PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT); - return NULL; -} - -static ocspCheckingContext * -ocsp_GetCheckingContext(CERTCertDBHandle *handle) -{ - CERTStatusConfig *statusConfig; - ocspCheckingContext *ocspcx = NULL; - - statusConfig = CERT_GetStatusConfig(handle); - if (statusConfig != NULL) { - ocspcx = statusConfig->statusContext; - - /* - * This is actually an internal error, because we should never - * have a good statusConfig without a good statusContext, too. - * For lack of anything better, though, we just assert and use - * the same error as if there were no statusConfig (set below). - */ - PORT_Assert(ocspcx != NULL); - } - - if (ocspcx == NULL) - PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED); - - return ocspcx; -} -/* - * Return true if the given signerCert is the default responder for - * the given certID. If not, or if any error, return false. - */ -static CERTCertificate * -ocsp_CertGetDefaultResponder(CERTCertDBHandle *handle,CERTOCSPCertID *certID) -{ - ocspCheckingContext *ocspcx; - - ocspcx = ocsp_GetCheckingContext(handle); - if (ocspcx == NULL) - goto loser; - - /* - * Right now we have only one default responder. It applies to - * all certs when it is used, so the check is simple and certID - * has no bearing on the answer. Someday in the future we may - * allow configuration of different responders for different - * issuers, and then we would have to use the issuer specified - * in certID to determine if signerCert is the right one. - */ - if (ocspcx->useDefaultResponder) { - PORT_Assert(ocspcx->defaultResponderCert != NULL); - return ocspcx->defaultResponderCert; - } - -loser: - return NULL; -} - -/* - * Return true if the given signerCert is the default responder for - * the given certID. If not, or if any error, return false. - */ -static PRBool -ocsp_CertIsDefaultResponderForCertID(CERTCertDBHandle *handle, - CERTCertificate *signerCert, - CERTOCSPCertID *certID) -{ - CERTCertificate *defaultResponderCert; - - defaultResponderCert = ocsp_CertGetDefaultResponder(handle, certID); - return (PRBool) (defaultResponderCert == signerCert); -} - -/* - * Check that the given signer certificate is authorized to sign status - * information for the given certID. Return true if it is, false if not - * (or if there is any error along the way). If false is returned because - * the signer is not authorized, the following error will be set: - * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE - * Other errors are low-level problems (no memory, bad database, etc.). - * - * There are three ways to be authorized. In the order in which we check, - * using the terms used in the OCSP spec, the signer must be one of: - * 1. A "trusted responder" -- it matches a local configuration - * of OCSP signing authority for the certificate in question. - * 2. The CA who issued the certificate in question. - * 3. A "CA designated responder", aka an "authorized responder" -- it - * must be represented by a special cert issued by the CA who issued - * the certificate in question. - */ -static PRBool -ocsp_AuthorizedResponderForCertID(CERTCertDBHandle *handle, - CERTCertificate *signerCert, - CERTOCSPCertID *certID, - int64 thisUpdate) -{ - CERTCertificate *issuerCert = NULL; - SECItem *issuerKeyHash = NULL; - SECOidTag hashAlg; - PRBool okay = PR_FALSE; - - /* - * Check first for a trusted responder, which overrides everything else. - */ - if (ocsp_CertIsDefaultResponderForCertID(handle, signerCert, certID)) - return PR_TRUE; - - /* - * In the other two cases, we need to do an issuer comparison. - * How we do it depends on whether the signer certificate has the - * special extension (for a designated responder) or not. - */ - - if (ocsp_CertIsOCSPSigner(signerCert)) { - /* - * The signer is a designated responder. Its issuer must match - * the issuer of the cert being checked. - */ - issuerCert = CERT_FindCertIssuer(signerCert, thisUpdate, - certUsageAnyCA); - if (issuerCert == NULL) { - /* - * We could leave the SEC_ERROR_UNKNOWN_ISSUER error alone, - * but the following will give slightly more information. - * Once we have an error stack, things will be much better. - */ - PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); - goto loser; - } - } else { - /* - * The signer must *be* the issuer of the cert being checked. - */ - issuerCert = signerCert; - } - - hashAlg = SECOID_FindOIDTag(&certID->hashAlgorithm.algorithm); - issuerKeyHash = CERT_SPKDigestValueForCert(NULL, issuerCert, hashAlg, NULL); - if (issuerKeyHash == NULL) - goto loser; - - if (SECITEM_CompareItem(issuerKeyHash, - &certID->issuerKeyHash) != SECEqual) { - PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE); - goto loser; - } - - okay = PR_TRUE; - -loser: - if (issuerKeyHash != NULL) - SECITEM_FreeItem(issuerKeyHash, PR_TRUE); - - if (issuerCert != NULL && issuerCert != signerCert) - CERT_DestroyCertificate(issuerCert); - - return okay; -} - -/* - * We need to check that a responder gives us "recent" information. - * Since a responder can pre-package responses, we need to pick an amount - * of time that is acceptable to us, and reject any response that is - * older than that. - * - * XXX This *should* be based on some configuration parameter, so that - * different usages could specify exactly what constitutes "sufficiently - * recent". But that is not going to happen right away. For now, we - * want something from within the last 24 hours. This macro defines that - * number in seconds. - */ -#define OCSP_ALLOWABLE_LAPSE_SECONDS (24L * 60L * 60L) - -static PRBool -ocsp_TimeIsRecent(int64 checkTime) -{ - int64 now = PR_Now(); - int64 lapse, tmp; - - LL_I2L(lapse, OCSP_ALLOWABLE_LAPSE_SECONDS); - LL_I2L(tmp, PR_USEC_PER_SEC); - LL_MUL(lapse, lapse, tmp); /* allowable lapse in microseconds */ - - LL_ADD(checkTime, checkTime, lapse); - if (LL_CMP(now, >, checkTime)) - return PR_FALSE; - - return PR_TRUE; -} - -#define OCSP_SLOP (5L*60L) /* OCSP responses are allowed to be 5 minutes - in the future by default */ - -static PRUint32 ocspsloptime = OCSP_SLOP; /* seconds */ - -/* - * Check that this single response is okay. A return of SECSuccess means: - * 1. The signer (represented by "signerCert") is authorized to give status - * for the cert represented by the individual response in "single". - * 2. The value of thisUpdate is earlier than now. - * 3. The value of producedAt is later than or the same as thisUpdate. - * 4. If nextUpdate is given: - * - The value of nextUpdate is later than now. - * - The value of producedAt is earlier than nextUpdate. - * Else if no nextUpdate: - * - The value of thisUpdate is fairly recent. - * - The value of producedAt is fairly recent. - * However we do not need to perform an explicit check for this last - * constraint because it is already guaranteed by checking that - * producedAt is later than thisUpdate and thisUpdate is recent. - * Oh, and any responder is "authorized" to say that a cert is unknown to it. - * - * If any of those checks fail, SECFailure is returned and an error is set: - * SEC_ERROR_OCSP_FUTURE_RESPONSE - * SEC_ERROR_OCSP_OLD_RESPONSE - * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE - * Other errors are low-level problems (no memory, bad database, etc.). - */ -static SECStatus -ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single, - CERTCertDBHandle *handle, - CERTCertificate *signerCert, - int64 producedAt) -{ - CERTOCSPCertID *certID = single->certID; - int64 now, thisUpdate, nextUpdate, tmstamp, tmp; - SECStatus rv; - - /* - * If all the responder said was that the given cert was unknown to it, - * that is a valid response. Not very interesting to us, of course, - * but all this function is concerned with is validity of the response, - * not the status of the cert. - */ - PORT_Assert(single->certStatus != NULL); - if (single->certStatus->certStatusType == ocspCertStatus_unknown) - return SECSuccess; - - /* - * We need to extract "thisUpdate" for use below and to pass along - * to AuthorizedResponderForCertID in case it needs it for doing an - * issuer look-up. - */ - rv = DER_GeneralizedTimeToTime(&thisUpdate, &single->thisUpdate); - if (rv != SECSuccess) - return rv; - - /* - * First confirm that signerCert is authorized to give this status. - */ - if (ocsp_AuthorizedResponderForCertID(handle, signerCert, certID, - thisUpdate) != PR_TRUE) - return SECFailure; - - /* - * Now check the time stuff, as described above. - */ - now = PR_Now(); - /* allow slop time for future response */ - LL_UI2L(tmstamp, ocspsloptime); /* get slop time in seconds */ - LL_UI2L(tmp, PR_USEC_PER_SEC); - LL_MUL(tmp, tmstamp, tmp); /* convert the slop time to PRTime */ - LL_ADD(tmstamp, tmp, now); /* add current time to it */ - - if (LL_CMP(thisUpdate, >, tmstamp) || LL_CMP(producedAt, <, thisUpdate)) { - PORT_SetError(SEC_ERROR_OCSP_FUTURE_RESPONSE); - return SECFailure; - } - if (single->nextUpdate != NULL) { - rv = DER_GeneralizedTimeToTime(&nextUpdate, single->nextUpdate); - if (rv != SECSuccess) - return rv; - - LL_ADD(tmp, tmp, nextUpdate); - if (LL_CMP(tmp, <, now) || LL_CMP(producedAt, >, nextUpdate)) { - PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE); - return SECFailure; - } - } else if (ocsp_TimeIsRecent(thisUpdate) != PR_TRUE) { - PORT_SetError(SEC_ERROR_OCSP_OLD_RESPONSE); - return SECFailure; - } - - return SECSuccess; -} - - -/* - * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation - * Get the value of the URI of the OCSP responder for the given cert. - * This is found in the (optional) Authority Information Access extension - * in the cert. - * INPUTS: - * CERTCertificate *cert - * The certificate being examined. - * RETURN: - * char * - * A copy of the URI for the OCSP method, if found. If either the - * extension is not present or it does not contain an entry for OCSP, - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION will be set and a NULL returned. - * Any other error will also result in a NULL being returned. - * - * This result should be freed (via PORT_Free) when no longer in use. - */ -char * -CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert) -{ - CERTGeneralName *locname = NULL; - SECItem *location = NULL; - SECItem *encodedAuthInfoAccess = NULL; - CERTAuthInfoAccess **authInfoAccess = NULL; - char *locURI = NULL; - PRArenaPool *arena = NULL; - SECStatus rv; - int i; - - /* - * Allocate this one from the heap because it will get filled in - * by CERT_FindCertExtension which will also allocate from the heap, - * and we can free the entire thing on our way out. - */ - encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0); - if (encodedAuthInfoAccess == NULL) - goto loser; - - rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, - encodedAuthInfoAccess); - if (rv == SECFailure) { - PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); - goto loser; - } - - /* - * The rest of the things allocated in the routine will come out of - * this arena, which is temporary just for us to decode and get at the - * AIA extension. The whole thing will be destroyed on our way out, - * after we have copied the location string (url) itself (if found). - */ - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) - goto loser; - - authInfoAccess = CERT_DecodeAuthInfoAccessExtension(arena, - encodedAuthInfoAccess); - if (authInfoAccess == NULL) - goto loser; - - for (i = 0; authInfoAccess[i] != NULL; i++) { - if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == SEC_OID_PKIX_OCSP) - locname = authInfoAccess[i]->location; - } - - /* - * If we found an AIA extension, but it did not include an OCSP method, - * that should look to our caller as if we did not find the extension - * at all, because it is only an OCSP method that we care about. - * So set the same error that would be set if the AIA extension was - * not there at all. - */ - if (locname == NULL) { - PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); - goto loser; - } - - /* - * The following is just a pointer back into locname (i.e. not a copy); - * thus it should not be freed. - */ - location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE); - if (location == NULL) { - /* - * XXX Appears that CERT_GetGeneralNameByType does not set an - * error if there is no name by that type. For lack of anything - * better, act as if the extension was not found. In the future - * this should probably be something more like the extension was - * badly formed. - */ - PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION); - goto loser; - } - - /* - * That location is really a string, but it has a specified length - * without a null-terminator. We need a real string that does have - * a null-terminator, and we need a copy of it anyway to return to - * our caller -- so allocate and copy. - */ - locURI = PORT_Alloc(location->len + 1); - if (locURI == NULL) { - goto loser; - } - PORT_Memcpy(locURI, location->data, location->len); - locURI[location->len] = '\0'; - -loser: - if (arena != NULL) - PORT_FreeArena(arena, PR_FALSE); - - if (encodedAuthInfoAccess != NULL) - SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE); - - return locURI; -} - - -/* - * Figure out where we should go to find out the status of the given cert - * via OCSP. If a default responder is set up, that is our answer. - * If not, see if the certificate has an Authority Information Access (AIA) - * extension for OCSP, and return the value of that. Otherwise return NULL. - * We also let our caller know whether or not the responder chosen was - * a default responder or not through the output variable isDefault; - * its value has no meaning unless a good (non-null) value is returned - * for the location. - * - * The result needs to be freed (PORT_Free) when no longer in use. - */ -static char * -ocsp_GetResponderLocation(CERTCertDBHandle *handle, CERTCertificate *cert, - PRBool *isDefault) -{ - ocspCheckingContext *ocspcx; - - ocspcx = ocsp_GetCheckingContext(handle); - if (ocspcx != NULL && ocspcx->useDefaultResponder) { - /* - * A default responder wins out, if specified. - * XXX Someday this may be a more complicated determination based - * on the cert's issuer. (That is, we could have different default - * responders configured for different issuers.) - */ - PORT_Assert(ocspcx->defaultResponderURI != NULL); - *isDefault = PR_TRUE; - return (PORT_Strdup(ocspcx->defaultResponderURI)); - } - - /* - * No default responder set up, so go see if we can find an AIA - * extension that has a value for OCSP, and get the url from that. - */ - *isDefault = PR_FALSE; - return CERT_GetOCSPAuthorityInfoAccessLocation(cert); -} - -/* - * Return SECSuccess if the cert was revoked *after* "time", - * SECFailure otherwise. - */ -static SECStatus -ocsp_CertRevokedAfter(ocspRevokedInfo *revokedInfo, int64 time) -{ - int64 revokedTime; - SECStatus rv; - - rv = DER_GeneralizedTimeToTime(&revokedTime, &revokedInfo->revocationTime); - if (rv != SECSuccess) - return rv; - - /* - * Set the error even if we will return success; someone might care. - */ - PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); - - if (LL_CMP(revokedTime, >, time)) - return SECSuccess; - - return SECFailure; -} - -/* - * See if the cert represented in the single response had a good status - * at the specified time. - */ -static SECStatus -ocsp_CertHasGoodStatus(CERTOCSPSingleResponse *single, int64 time) -{ - ocspCertStatus *status; - SECStatus rv; - - status = single->certStatus; - - switch (status->certStatusType) { - case ocspCertStatus_good: - rv = SECSuccess; - break; - case ocspCertStatus_revoked: - rv = ocsp_CertRevokedAfter(status->certStatusInfo.revokedInfo, time); - break; - case ocspCertStatus_unknown: - PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT); - rv = SECFailure; - break; - case ocspCertStatus_other: - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); - rv = SECFailure; - break; - } - - return rv; -} - - -/* - * FUNCTION: CERT_CheckOCSPStatus - * Checks the status of a certificate via OCSP. Will only check status for - * a certificate that has an AIA (Authority Information Access) extension - * for OCSP *or* when a "default responder" is specified and enabled. - * (If no AIA extension for OCSP and no default responder in place, the - * cert is considered to have a good status and SECSuccess is returned.) - * INPUTS: - * CERTCertDBHandle *handle - * certificate DB of the cert that is being checked - * CERTCertificate *cert - * the certificate being checked - * XXX in the long term also need a boolean parameter that specifies - * whether to check the cert chain, as well; for now we check only - * the leaf (the specified certificate) - * int64 time - * time for which status is to be determined - * void *pwArg - * argument for password prompting, if needed - * RETURN: - * Returns SECSuccess if an approved OCSP responder "knows" the cert - * *and* returns a non-revoked status for it; SECFailure otherwise, - * with an error set describing the reason: - * - * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE - * SEC_ERROR_OCSP_FUTURE_RESPONSE - * SEC_ERROR_OCSP_MALFORMED_REQUEST - * SEC_ERROR_OCSP_MALFORMED_RESPONSE - * SEC_ERROR_OCSP_OLD_RESPONSE - * SEC_ERROR_OCSP_REQUEST_NEEDS_SIG - * SEC_ERROR_OCSP_SERVER_ERROR - * SEC_ERROR_OCSP_TRY_SERVER_LATER - * SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST - * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE - * SEC_ERROR_OCSP_UNKNOWN_CERT - * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS - * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE - * - * SEC_ERROR_BAD_SIGNATURE - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION - * SEC_ERROR_INVALID_TIME - * SEC_ERROR_REVOKED_CERTIFICATE - * SEC_ERROR_UNKNOWN_ISSUER - * SEC_ERROR_UNKNOWN_SIGNER - * - * Other errors are any of the many possible failures in cert verification - * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when - * verifying the signer's cert, or low-level problems (error allocating - * memory, error performing ASN.1 decoding, etc.). - */ -SECStatus -CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert, - int64 time, void *pwArg) -{ - char *location = NULL; - PRBool locationIsDefault; - CERTCertList *certList = NULL; - SECItem *encodedResponse = NULL; - CERTOCSPRequest *request = NULL; - CERTOCSPResponse *response = NULL; - CERTCertificate *signerCert = NULL; - CERTCertificate *issuerCert = NULL; - CERTOCSPCertID *certID; - SECStatus rv = SECFailure; - - - /* - * The first thing we need to do is find the location of the responder. - * This will be the value of the default responder (if enabled), else - * it will come out of the AIA extension in the cert (if present). - * If we have no such location, then this cert does not "deserve" to - * be checked -- that is, we consider it a success and just return. - * The way we tell that is by looking at the error number to see if - * the problem was no AIA extension was found; any other error was - * a true failure that we unfortunately have to treat as an overall - * failure here. - */ - location = ocsp_GetResponderLocation(handle, cert, &locationIsDefault); - if (location == NULL) { - int err = PORT_GetError(); - if (err == SEC_ERROR_EXTENSION_NOT_FOUND || - err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { - PORT_SetError(0); - return SECSuccess; - } - return SECFailure; - } - - /* - * For now, create a cert-list of one. - * XXX In the fullness of time, we will want/need to handle a - * certificate chain. This will be done either when a new parameter - * tells us to, or some configuration variable tells us to. In any - * case, handling it is complicated because we may need to send as - * many requests (and receive as many responses) as we have certs - * in the chain. If we are going to talk to a default responder, - * and we only support one default responder, we can put all of the - * certs together into one request. Otherwise, we must break them up - * into multiple requests. (Even if all of the requests will go to - * the same location, the signature on each response will be different, - * because each issuer is different. Carefully read the OCSP spec - * if you do not understand this.) - */ - - certList = CERT_NewCertList(); - if (certList == NULL) - goto loser; - - /* dup it because freeing the list will destroy the cert, too */ - cert = CERT_DupCertificate(cert); - if (cert == NULL) - goto loser; - - if (CERT_AddCertToListTail(certList, cert) != SECSuccess) { - CERT_DestroyCertificate(cert); - goto loser; - } - - /* - * XXX If/when signing of requests is supported, that second NULL - * should be changed to be the signer certificate. Not sure if that - * should be passed into this function or retrieved via some operation - * on the handle/context. - */ - encodedResponse = CERT_GetEncodedOCSPResponse(NULL, certList, location, - time, locationIsDefault, - NULL, pwArg, &request); - if (encodedResponse == NULL) { - goto loser; - } - - response = CERT_DecodeOCSPResponse(encodedResponse); - if (response == NULL) { - goto loser; - } - - /* - * Okay, we at least have a response that *looks* like a response! - * Now see if the overall response status value is good or not. - * If not, we set an error and give up. (It means that either the - * server had a problem, or it didn't like something about our - * request. Either way there is nothing to do but give up.) - * Otherwise, we continue to find the actual per-cert status - * in the response. - */ - if (CERT_GetOCSPResponseStatus(response) != SECSuccess) { - goto loser; - } - - /* - * If we've made it this far, we expect a response with a good signature. - * So, check for that. - */ - issuerCert = CERT_FindCertIssuer(cert, time, certUsageAnyCA); - rv = CERT_VerifyOCSPResponseSignature(response, handle, pwArg, &signerCert, - issuerCert); - if (rv != SECSuccess) - goto loser; - - PORT_Assert(signerCert != NULL); /* internal consistency check */ - /* XXX probably should set error, return failure if signerCert is null */ - - - /* - * Again, we are only doing one request for one cert. - * XXX When we handle cert chains, the following code will obviously - * have to be modified, in coordation with the code above that will - * have to determine how to make multiple requests, etc. It will need - * to loop, and for each certID in the request, find the matching - * single response and check the status specified by it. - * - * We are helped here in that we know that the requests are made with - * the request list in the same order as the order of the certs we hand - * to it. This is why I can directly access the first member of the - * single request array for the one cert I care about. - */ - - certID = request->tbsRequest->requestList[0]->reqCert; - rv = CERT_GetOCSPStatusForCertID(handle, response, certID, - signerCert, time); -loser: - if (issuerCert != NULL) - CERT_DestroyCertificate(issuerCert); - if (signerCert != NULL) - CERT_DestroyCertificate(signerCert); - if (response != NULL) - CERT_DestroyOCSPResponse(response); - if (request != NULL) - CERT_DestroyOCSPRequest(request); - if (encodedResponse != NULL) - SECITEM_FreeItem(encodedResponse, PR_TRUE); - if (certList != NULL) - CERT_DestroyCertList(certList); - if (location != NULL) - PORT_Free(location); - return rv; -} - -SECStatus -CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, - CERTOCSPResponse *response, - CERTOCSPCertID *certID, - CERTCertificate *signerCert, - int64 time) -{ - SECStatus rv; - ocspResponseData *responseData; - int64 producedAt; - CERTOCSPSingleResponse *single; - - /* - * The ResponseData part is the real guts of the response. - */ - responseData = ocsp_GetResponseData(response); - if (responseData == NULL) { - rv = SECFailure; - goto loser; - } - - /* - * There is one producedAt time for the entire response (and a separate - * thisUpdate time for each individual single response). We need to - * compare them, so get the overall time to pass into the check of each - * single response. - */ - rv = DER_GeneralizedTimeToTime(&producedAt, &responseData->producedAt); - if (rv != SECSuccess) - goto loser; - - single = ocsp_GetSingleResponseForCertID(responseData->responses, - handle, certID); - if (single == NULL) { - rv = SECFailure; - goto loser; - } - - rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt); - if (rv != SECSuccess) - goto loser; - - /* - * Okay, the last step is to check whether the status says revoked, - * and if so how that compares to the time value passed into this routine. - */ - - rv = ocsp_CertHasGoodStatus(single, time); -loser: - return rv; -} - - -/* - * Disable status checking and destroy related structures/data. - */ -static SECStatus -ocsp_DestroyStatusChecking(CERTStatusConfig *statusConfig) -{ - ocspCheckingContext *statusContext; - - /* - * Disable OCSP checking - */ - statusConfig->statusChecker = NULL; - - statusContext = statusConfig->statusContext; - PORT_Assert(statusContext != NULL); - if (statusContext == NULL) - return SECFailure; - - if (statusContext->defaultResponderURI != NULL) - PORT_Free(statusContext->defaultResponderURI); - if (statusContext->defaultResponderNickname != NULL) - PORT_Free(statusContext->defaultResponderNickname); - - PORT_Free(statusContext); - statusConfig->statusContext = NULL; - - PORT_Free(statusConfig); - - return SECSuccess; -} - - -/* - * FUNCTION: CERT_DisableOCSPChecking - * Turns off OCSP checking for the given certificate database. - * This routine disables OCSP checking. Though it will return - * SECFailure if OCSP checking is not enabled, it is "safe" to - * call it that way and just ignore the return value, if it is - * easier to just call it than to "remember" whether it is enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Certificate database for which OCSP checking will be disabled. - * RETURN: - * Returns SECFailure if an error occurred (usually means that OCSP - * checking was not enabled or status contexts were not initialized -- - * error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise. - */ -SECStatus -CERT_DisableOCSPChecking(CERTCertDBHandle *handle) -{ - CERTStatusConfig *statusConfig; - ocspCheckingContext *statusContext; - - if (handle == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - statusConfig = CERT_GetStatusConfig(handle); - statusContext = ocsp_GetCheckingContext(handle); - if (statusContext == NULL) - return SECFailure; - - if (statusConfig->statusChecker != CERT_CheckOCSPStatus) { - /* - * Status configuration is present, but either not currently - * enabled or not for OCSP. - */ - PORT_SetError(SEC_ERROR_OCSP_NOT_ENABLED); - return SECFailure; - } - - /* - * This is how we disable status checking. Everything else remains - * in place in case we are enabled again. - */ - statusConfig->statusChecker = NULL; - - return SECSuccess; -} - -/* - * Allocate and initialize the informational structures for status checking. - * This is done when some configuration of OCSP is being done or when OCSP - * checking is being turned on, whichever comes first. - */ -static SECStatus -ocsp_InitStatusChecking(CERTCertDBHandle *handle) -{ - CERTStatusConfig *statusConfig = NULL; - ocspCheckingContext *statusContext = NULL; - - PORT_Assert(CERT_GetStatusConfig(handle) == NULL); - if (CERT_GetStatusConfig(handle) != NULL) { - /* XXX or call statusConfig->statusDestroy and continue? */ - return SECFailure; - } - - statusConfig = PORT_ZNew(CERTStatusConfig); - if (statusConfig == NULL) - goto loser; - - statusContext = PORT_ZNew(ocspCheckingContext); - if (statusContext == NULL) - goto loser; - - statusConfig->statusDestroy = ocsp_DestroyStatusChecking; - statusConfig->statusContext = statusContext; - - CERT_SetStatusConfig(handle, statusConfig); - - return SECSuccess; - -loser: - if (statusConfig != NULL) - PORT_Free(statusConfig); - return SECFailure; -} - - -/* - * FUNCTION: CERT_EnableOCSPChecking - * Turns on OCSP checking for the given certificate database. - * INPUTS: - * CERTCertDBHandle *handle - * Certificate database for which OCSP checking will be enabled. - * RETURN: - * Returns SECFailure if an error occurred (likely only problem - * allocating memory); SECSuccess otherwise. - */ -SECStatus -CERT_EnableOCSPChecking(CERTCertDBHandle *handle) -{ - CERTStatusConfig *statusConfig; - - SECStatus rv; - - if (handle == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - statusConfig = CERT_GetStatusConfig(handle); - if (statusConfig == NULL) { - rv = ocsp_InitStatusChecking(handle); - if (rv != SECSuccess) - return rv; - - /* Get newly established value */ - statusConfig = CERT_GetStatusConfig(handle); - PORT_Assert(statusConfig != NULL); - } - - /* - * Setting the checker function is what really enables the checking - * when each cert verification is done. - */ - statusConfig->statusChecker = CERT_CheckOCSPStatus; - - return SECSuccess; -} - - -/* - * FUNCTION: CERT_SetOCSPDefaultResponder - * Specify the location and cert of the default responder. - * If OCSP checking is already enabled *and* use of a default responder - * is also already enabled, all OCSP checking from now on will go directly - * to the specified responder. If OCSP checking is not enabled, or if - * it is but use of a default responder is not enabled, the information - * will be recorded and take effect whenever both are enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should use the default responder. - * char *url - * The location of the default responder (e.g. "http://foo.com:80/ocsp") - * Note that the location will not be tested until the first attempt - * to send a request there. - * char *name - * The nickname of the cert to trust (expected) to sign the OCSP responses. - * If the corresponding cert cannot be found, SECFailure is returned. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * The most likely error is that the cert for "name" could not be found - * (probably SEC_ERROR_UNKNOWN_CERT). Other errors are low-level (no memory, - * bad database, etc.). - */ -SECStatus -CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle, - const char *url, const char *name) -{ - CERTCertificate *cert; - ocspCheckingContext *statusContext; - char *url_copy = NULL; - char *name_copy = NULL; - SECStatus rv; - - if (handle == NULL || url == NULL || name == NULL) { - /* - * XXX When interface is exported, probably want better errors; - * perhaps different one for each parameter. - */ - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - /* - * Find the certificate for the specified nickname. Do this first - * because it seems the most likely to fail. - * - * XXX Shouldn't need that cast if the FindCertByNickname interface - * used const to convey that it does not modify the name. Maybe someday. - */ - cert = CERT_FindCertByNickname(handle, (char *) name); - if (cert == NULL) { - /* - * look for the cert on an external token. - */ - cert = PK11_FindCertFromNickname((char *)name, NULL); - } - if (cert == NULL) - return SECFailure; - - /* - * Make a copy of the url and nickname. - */ - url_copy = PORT_Strdup(url); - name_copy = PORT_Strdup(name); - if (url_copy == NULL || name_copy == NULL) { - rv = SECFailure; - goto loser; - } - - statusContext = ocsp_GetCheckingContext(handle); - - /* - * Allocate and init the context if it doesn't already exist. - */ - if (statusContext == NULL) { - rv = ocsp_InitStatusChecking(handle); - if (rv != SECSuccess) - goto loser; - - statusContext = ocsp_GetCheckingContext(handle); - PORT_Assert(statusContext != NULL); /* extreme paranoia */ - } - - /* - * Note -- we do not touch the status context until after all of - * the steps which could cause errors. If something goes wrong, - * we want to leave things as they were. - */ - - /* - * Get rid of old url and name if there. - */ - if (statusContext->defaultResponderNickname != NULL) - PORT_Free(statusContext->defaultResponderNickname); - if (statusContext->defaultResponderURI != NULL) - PORT_Free(statusContext->defaultResponderURI); - - /* - * And replace them with the new ones. - */ - statusContext->defaultResponderURI = url_copy; - statusContext->defaultResponderNickname = name_copy; - - /* - * If there was already a cert in place, get rid of it and replace it. - * Otherwise, we are not currently enabled, so we don't want to save it; - * it will get re-found and set whenever use of a default responder is - * enabled. - */ - if (statusContext->defaultResponderCert != NULL) { - CERT_DestroyCertificate(statusContext->defaultResponderCert); - statusContext->defaultResponderCert = cert; - } else { - PORT_Assert(statusContext->useDefaultResponder == PR_FALSE); - CERT_DestroyCertificate(cert); - } - - return SECSuccess; - -loser: - CERT_DestroyCertificate(cert); - if (url_copy != NULL) - PORT_Free(url_copy); - if (name_copy != NULL) - PORT_Free(name_copy); - return rv; -} - - -/* - * FUNCTION: CERT_EnableOCSPDefaultResponder - * Turns on use of a default responder when OCSP checking. - * If OCSP checking is already enabled, this will make subsequent checks - * go directly to the default responder. (The location of the responder - * and the nickname of the responder cert must already be specified.) - * If OCSP checking is not enabled, this will be recorded and take effect - * whenever it is enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should use the default responder. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * No errors are especially likely unless the caller did not previously - * perform a successful call to SetOCSPDefaultResponder (in which case - * the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER). - */ -SECStatus -CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle) -{ - ocspCheckingContext *statusContext; - CERTCertificate *cert; - - if (handle == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - statusContext = ocsp_GetCheckingContext(handle); - - if (statusContext == NULL) { - /* - * Strictly speaking, the error already set is "correct", - * but cover over it with one more helpful in this context. - */ - PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); - return SECFailure; - } - - if (statusContext->defaultResponderURI == NULL) { - PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); - return SECFailure; - } - - if (statusContext->defaultResponderNickname == NULL) { - PORT_SetError(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER); - return SECFailure; - } - - /* - * Find the cert for the nickname. - */ - cert = CERT_FindCertByNickname(handle, - statusContext->defaultResponderNickname); - if (cert == NULL) { - cert = PK11_FindCertFromNickname(statusContext->defaultResponderNickname, - NULL); - } - /* - * We should never have trouble finding the cert, because its - * existence should have been proven by SetOCSPDefaultResponder. - */ - PORT_Assert(cert != NULL); - if (cert == NULL) - return SECFailure; - - /* - * And hang onto it. - */ - statusContext->defaultResponderCert = cert; - - /* - * Finally, record the fact that we now have a default responder enabled. - */ - statusContext->useDefaultResponder = PR_TRUE; - return SECSuccess; -} - - -/* - * FUNCTION: CERT_DisableOCSPDefaultResponder - * Turns off use of a default responder when OCSP checking. - * (Does nothing if use of a default responder is not enabled.) - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should stop using a default - * responder. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * Errors very unlikely (like random memory corruption...). - */ -SECStatus -CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle) -{ - CERTStatusConfig *statusConfig; - ocspCheckingContext *statusContext; - - if (handle == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - statusConfig = CERT_GetStatusConfig(handle); - if (statusConfig == NULL) - return SECSuccess; - - statusContext = ocsp_GetCheckingContext(handle); - PORT_Assert(statusContext != NULL); - if (statusContext == NULL) - return SECFailure; - - if (statusContext->defaultResponderCert != NULL) { - CERT_DestroyCertificate(statusContext->defaultResponderCert); - statusContext->defaultResponderCert = NULL; - } - - /* - * Finally, record the fact. - */ - statusContext->useDefaultResponder = PR_FALSE; - return SECSuccess; -} - -/* - * Digest the cert's subject public key using the specified algorithm. - * The necessary storage for the digest data is allocated. If "fill" is - * non-null, the data is put there, otherwise a SECItem is allocated. - * Allocation from "arena" if it is non-null, heap otherwise. Any problem - * results in a NULL being returned (and an appropriate error set). - */ -SECItem * -CERT_SPKDigestValueForCert(PRArenaPool *arena, CERTCertificate *cert, - SECOidTag digestAlg, SECItem *fill) -{ - const SECHashObject *digestObject; - void *digestContext; - SECItem *result = NULL; - void *mark = NULL; - SECItem spk; - - if ( arena != NULL ) { - mark = PORT_ArenaMark(arena); - } - - digestObject = HASH_GetHashObjectByOidTag(digestAlg); - if ( digestObject == NULL ) { - goto loser; - } - - if ((fill == NULL) || (fill->data == NULL)) { - result = SECITEM_AllocItem(arena, fill, digestObject->length); - if ( result == NULL ) { - goto loser; - } - fill = result; - } - - /* - * Copy just the length and data pointer (nothing needs to be freed) - * of the subject public key so we can convert the length from bits - * to bytes, which is what the digest function expects. - */ - spk = cert->subjectPublicKeyInfo.subjectPublicKey; - DER_ConvertBitString(&spk); - - /* - * Now digest the value, using the specified algorithm. - */ - digestContext = digestObject->create(); - if ( digestContext == NULL ) { - goto loser; - } - digestObject->begin(digestContext); - digestObject->update(digestContext, spk.data, spk.len); - digestObject->end(digestContext, fill->data, &(fill->len), fill->len); - digestObject->destroy(digestContext, PR_TRUE); - - if ( arena != NULL ) { - PORT_ArenaUnmark(arena, mark); - } - return(fill); - -loser: - if ( arena != NULL ) { - PORT_ArenaRelease(arena, mark); - } else { - if ( result != NULL ) { - SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE); - } - } - return(NULL); -} - -SECStatus -CERT_GetOCSPResponseStatus(CERTOCSPResponse *response) -{ - PORT_Assert(response); - if (response->statusValue == ocspResponse_successful) - return SECSuccess; - - switch (response->statusValue) { - case ocspResponse_malformedRequest: - PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST); - break; - case ocspResponse_internalError: - PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR); - break; - case ocspResponse_tryLater: - PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER); - break; - case ocspResponse_sigRequired: - /* XXX We *should* retry with a signature, if possible. */ - PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG); - break; - case ocspResponse_unauthorized: - PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); - break; - case ocspResponse_other: - case ocspResponse_unused: - default: - PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); - break; - } - return SECFailure; -} diff --git a/security/nss/lib/certhigh/ocsp.h b/security/nss/lib/certhigh/ocsp.h deleted file mode 100644 index 810bc010c..000000000 --- a/security/nss/lib/certhigh/ocsp.h +++ /dev/null @@ -1,549 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Interface to the OCSP implementation. - * - * $Id$ - */ - -#ifndef _OCSP_H_ -#define _OCSP_H_ - - -#include "plarena.h" -#include "seccomon.h" -#include "secoidt.h" -#include "keyt.h" -#include "certt.h" -#include "ocspt.h" - - -/************************************************************************/ -SEC_BEGIN_PROTOS - -/* - * This function registers the HttpClient with whose functions the - * HttpClientFcn structure have been populated as the default Http - * client. - * - * The function table must be a global object. - * The caller must ensure that NSS will be able to call - * the registered functions for the lifetime of the process. - */ -extern SECStatus -SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable); - -/* - * FUNCTION: CERT_EnableOCSPChecking - * Turns on OCSP checking for the given certificate database. - * INPUTS: - * CERTCertDBHandle *handle - * Certificate database for which OCSP checking will be enabled. - * RETURN: - * Returns SECFailure if an error occurred (likely only problem - * allocating memory); SECSuccess otherwise. - */ -extern SECStatus -CERT_EnableOCSPChecking(CERTCertDBHandle *handle); - -/* - * FUNCTION: CERT_DisableOCSPChecking - * Turns off OCSP checking for the given certificate database. - * This routine disables OCSP checking. Though it will return - * SECFailure if OCSP checking is not enabled, it is "safe" to - * call it that way and just ignore the return value, if it is - * easier to just call it than to "remember" whether it is enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Certificate database for which OCSP checking will be disabled. - * RETURN: - * Returns SECFailure if an error occurred (usually means that OCSP - * checking was not enabled or status contexts were not initialized -- - * error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise. - */ -extern SECStatus -CERT_DisableOCSPChecking(CERTCertDBHandle *handle); - -/* - * FUNCTION: CERT_SetOCSPDefaultResponder - * Specify the location and cert of the default responder. - * If OCSP checking is already enabled *and* use of a default responder - * is also already enabled, all OCSP checking from now on will go directly - * to the specified responder. If OCSP checking is not enabled, or if - * it is but use of a default responder is not enabled, the information - * will be recorded and take effect whenever both are enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should use the default responder. - * char *url - * The location of the default responder (e.g. "http://foo.com:80/ocsp") - * Note that the location will not be tested until the first attempt - * to send a request there. - * char *name - * The nickname of the cert to trust (expected) to sign the OCSP responses. - * If the corresponding cert cannot be found, SECFailure is returned. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * The most likely error is that the cert for "name" could not be found - * (probably SEC_ERROR_UNKNOWN_CERT). Other errors are low-level (no memory, - * bad database, etc.). - */ -extern SECStatus -CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle, - const char *url, const char *name); - -/* - * FUNCTION: CERT_EnableOCSPDefaultResponder - * Turns on use of a default responder when OCSP checking. - * If OCSP checking is already enabled, this will make subsequent checks - * go directly to the default responder. (The location of the responder - * and the nickname of the responder cert must already be specified.) - * If OCSP checking is not enabled, this will be recorded and take effect - * whenever it is enabled. - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should use the default responder. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * No errors are especially likely unless the caller did not previously - * perform a successful call to SetOCSPDefaultResponder (in which case - * the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER). - */ -extern SECStatus -CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle); - -/* - * FUNCTION: CERT_DisableOCSPDefaultResponder - * Turns off use of a default responder when OCSP checking. - * (Does nothing if use of a default responder is not enabled.) - * INPUTS: - * CERTCertDBHandle *handle - * Cert database on which OCSP checking should stop using a default - * responder. - * RETURN: - * Returns SECFailure if an error occurred; SECSuccess otherwise. - * Errors very unlikely (like random memory corruption...). - */ -extern SECStatus -CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle); - -/* - * ------------------------------------------------------- - * The Functions above are those expected to be used by a client - * providing OCSP status checking along with every cert verification. - * The functions below are for OCSP testing, debugging, or clients - * or servers performing more specialized OCSP tasks. - * ------------------------------------------------------- - */ - -/* - * FUNCTION: CERT_CreateOCSPRequest - * Creates a CERTOCSPRequest, requesting the status of the certs in - * the given list. - * INPUTS: - * CERTCertList *certList - * A list of certs for which status will be requested. - * Note that all of these certificates should have the same issuer, - * or it's expected the response will be signed by a trusted responder. - * If the certs need to be broken up into multiple requests, that - * must be handled by the caller (and thus by having multiple calls - * to this routine), who knows about where the request(s) are being - * sent and whether there are any trusted responders in place. - * int64 time - * Indicates the time for which the certificate status is to be - * determined -- this may be used in the search for the cert's issuer - * but has no effect on the request itself. - * PRBool addServiceLocator - * If true, the Service Locator extension should be added to the - * single request(s) for each cert. - * CERTCertificate *signerCert - * If non-NULL, means sign the request using this cert. Otherwise, - * do not sign. - * XXX note that request signing is not yet supported; see comment in code - * RETURN: - * A pointer to a CERTOCSPRequest structure containing an OCSP request - * for the cert list. On error, null is returned, with an error set - * indicating the reason. This is likely SEC_ERROR_UNKNOWN_ISSUER. - * (The issuer is needed to create a request for the certificate.) - * Other errors are low-level problems (no memory, bad database, etc.). - */ -extern CERTOCSPRequest * -CERT_CreateOCSPRequest(CERTCertList *certList, int64 time, - PRBool addServiceLocator, - CERTCertificate *signerCert); - -/* - * FUNCTION: CERT_AddOCSPAcceptableResponses - * Add the AcceptableResponses extension to an OCSP Request. - * INPUTS: - * CERTOCSPRequest *request - * The request to which the extension should be added. - * SECOidTag responseType0, ... - * A list (of one or more) of SECOidTag -- each of the response types - * to be added. The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE. - * (This marks the end of the list, and it must be specified because a - * client conforming to the OCSP standard is required to handle the basic - * response type.) The OIDs are not checked in any way. - * RETURN: - * SECSuccess if the extension is added; SECFailure if anything goes wrong. - * All errors are internal or low-level problems (e.g. no memory). - */ -extern SECStatus -CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request, - SECOidTag responseType0, ...); - -/* - * FUNCTION: CERT_EncodeOCSPRequest - * DER encodes an OCSP Request, possibly adding a signature as well. - * XXX Signing is not yet supported, however; see comments in code. - * INPUTS: - * PRArenaPool *arena - * The return value is allocated from here. - * If a NULL is passed in, allocation is done from the heap instead. - * CERTOCSPRequest *request - * The request to be encoded. - * void *pwArg - * Pointer to argument for password prompting, if needed. (Definitely - * not needed if not signing.) - * RETURN: - * Returns a NULL on error and a pointer to the SECItem with the - * encoded value otherwise. Any error is likely to be low-level - * (e.g. no memory). - */ -extern SECItem * -CERT_EncodeOCSPRequest(PRArenaPool *arena, CERTOCSPRequest *request, - void *pwArg); - -/* - * FUNCTION: CERT_DecodeOCSPRequest - * Decode a DER encoded OCSP Request. - * INPUTS: - * SECItem *src - * Pointer to a SECItem holding DER encoded OCSP Request. - * RETURN: - * Returns a pointer to a CERTOCSPRequest containing the decoded request. - * On error, returns NULL. Most likely error is trouble decoding - * (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory). - */ -extern CERTOCSPRequest * -CERT_DecodeOCSPRequest(SECItem *src); - -/* - * FUNCTION: CERT_DestroyOCSPRequest - * Frees an OCSP Request structure. - * INPUTS: - * CERTOCSPRequest *request - * Pointer to CERTOCSPRequest to be freed. - * RETURN: - * No return value; no errors. - */ -extern void -CERT_DestroyOCSPRequest(CERTOCSPRequest *request); - -/* - * FUNCTION: CERT_DecodeOCSPResponse - * Decode a DER encoded OCSP Response. - * INPUTS: - * SECItem *src - * Pointer to a SECItem holding DER encoded OCSP Response. - * RETURN: - * Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response); - * the caller is responsible for destroying it. Or NULL if error (either - * response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE), - * it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE), - * or a low-level or internal error occurred). - */ -extern CERTOCSPResponse * -CERT_DecodeOCSPResponse(SECItem *src); - -/* - * FUNCTION: CERT_DestroyOCSPResponse - * Frees an OCSP Response structure. - * INPUTS: - * CERTOCSPResponse *request - * Pointer to CERTOCSPResponse to be freed. - * RETURN: - * No return value; no errors. - */ -extern void -CERT_DestroyOCSPResponse(CERTOCSPResponse *response); - -/* - * FUNCTION: CERT_GetEncodedOCSPResponse - * Creates and sends a request to an OCSP responder, then reads and - * returns the (encoded) response. - * INPUTS: - * PRArenaPool *arena - * Pointer to arena from which return value will be allocated. - * If NULL, result will be allocated from the heap (and thus should - * be freed via SECITEM_FreeItem). - * CERTCertList *certList - * A list of certs for which status will be requested. - * Note that all of these certificates should have the same issuer, - * or it's expected the response will be signed by a trusted responder. - * If the certs need to be broken up into multiple requests, that - * must be handled by the caller (and thus by having multiple calls - * to this routine), who knows about where the request(s) are being - * sent and whether there are any trusted responders in place. - * char *location - * The location of the OCSP responder (a URL). - * int64 time - * Indicates the time for which the certificate status is to be - * determined -- this may be used in the search for the cert's issuer - * but has no other bearing on the operation. - * PRBool addServiceLocator - * If true, the Service Locator extension should be added to the - * single request(s) for each cert. - * CERTCertificate *signerCert - * If non-NULL, means sign the request using this cert. Otherwise, - * do not sign. - * void *pwArg - * Pointer to argument for password prompting, if needed. (Definitely - * not needed if not signing.) - * OUTPUTS: - * CERTOCSPRequest **pRequest - * Pointer in which to store the OCSP request created for the given - * list of certificates. It is only filled in if the entire operation - * is successful and the pointer is not null -- and in that case the - * caller is then reponsible for destroying it. - * RETURN: - * Returns a pointer to the SECItem holding the response. - * On error, returns null with error set describing the reason: - * SEC_ERROR_UNKNOWN_ISSUER - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION - * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE - * Other errors are low-level problems (no memory, bad database, etc.). - */ -extern SECItem * -CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList, - char *location, int64 time, - PRBool addServiceLocator, - CERTCertificate *signerCert, void *pwArg, - CERTOCSPRequest **pRequest); - -/* - * FUNCTION: CERT_VerifyOCSPResponseSignature - * Check the signature on an OCSP Response. Will also perform a - * verification of the signer's certificate. Note, however, that a - * successful verification does not make any statement about the - * signer's *authority* to provide status for the certificate(s), - * that must be checked individually for each certificate. - * INPUTS: - * CERTOCSPResponse *response - * Pointer to response structure with signature to be checked. - * CERTCertDBHandle *handle - * Pointer to CERTCertDBHandle for certificate DB to use for verification. - * void *pwArg - * Pointer to argument for password prompting, if needed. - * CERTCertificate *issuerCert - * Issuer of the certificate that generated the OCSP request. - * OUTPUTS: - * CERTCertificate **pSignerCert - * Pointer in which to store signer's certificate; only filled-in if - * non-null. - * RETURN: - * Returns SECSuccess when signature is valid, anything else means invalid. - * Possible errors set: - * SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID - * SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time - * SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found - * SEC_ERROR_BAD_SIGNATURE - the signature did not verify - * Other errors are any of the many possible failures in cert verification - * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when - * verifying the signer's cert, or low-level problems (no memory, etc.) - */ -extern SECStatus -CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response, - CERTCertDBHandle *handle, void *pwArg, - CERTCertificate **pSignerCert, - CERTCertificate *issuerCert); - -/* - * FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation - * Get the value of the URI of the OCSP responder for the given cert. - * This is found in the (optional) Authority Information Access extension - * in the cert. - * INPUTS: - * CERTCertificate *cert - * The certificate being examined. - * RETURN: - * char * - * A copy of the URI for the OCSP method, if found. If either the - * extension is not present or it does not contain an entry for OCSP, - * SEC_ERROR_EXTENSION_NOT_FOUND will be set and a NULL returned. - * Any other error will also result in a NULL being returned. - * - * This result should be freed (via PORT_Free) when no longer in use. - */ -extern char * -CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert); - -/* - * FUNCTION: CERT_CheckOCSPStatus - * Checks the status of a certificate via OCSP. Will only check status for - * a certificate that has an AIA (Authority Information Access) extension - * for OCSP *or* when a "default responder" is specified and enabled. - * (If no AIA extension for OCSP and no default responder in place, the - * cert is considered to have a good status and SECSuccess is returned.) - * INPUTS: - * CERTCertDBHandle *handle - * certificate DB of the cert that is being checked - * CERTCertificate *cert - * the certificate being checked - * XXX in the long term also need a boolean parameter that specifies - * whether to check the cert chain, as well; for now we check only - * the leaf (the specified certificate) - * int64 time - * time for which status is to be determined - * void *pwArg - * argument for password prompting, if needed - * RETURN: - * Returns SECSuccess if an approved OCSP responder "knows" the cert - * *and* returns a non-revoked status for it; SECFailure otherwise, - * with an error set describing the reason: - * - * SEC_ERROR_OCSP_BAD_HTTP_RESPONSE - * SEC_ERROR_OCSP_FUTURE_RESPONSE - * SEC_ERROR_OCSP_MALFORMED_REQUEST - * SEC_ERROR_OCSP_MALFORMED_RESPONSE - * SEC_ERROR_OCSP_OLD_RESPONSE - * SEC_ERROR_OCSP_REQUEST_NEEDS_SIG - * SEC_ERROR_OCSP_SERVER_ERROR - * SEC_ERROR_OCSP_TRY_SERVER_LATER - * SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST - * SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE - * SEC_ERROR_OCSP_UNKNOWN_CERT - * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS - * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE - * - * SEC_ERROR_BAD_SIGNATURE - * SEC_ERROR_CERT_BAD_ACCESS_LOCATION - * SEC_ERROR_INVALID_TIME - * SEC_ERROR_REVOKED_CERTIFICATE - * SEC_ERROR_UNKNOWN_ISSUER - * SEC_ERROR_UNKNOWN_SIGNER - * - * Other errors are any of the many possible failures in cert verification - * (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when - * verifying the signer's cert, or low-level problems (error allocating - * memory, error performing ASN.1 decoding, etc.). - */ -extern SECStatus -CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert, - int64 time, void *pwArg); -/* - * FUNCTION: CERT_GetOCSPStatusForCertID - * Returns the OCSP status contained in the passed in paramter response - * that corresponds to the certID passed in. - * INPUTS: - * CERTCertDBHandle *handle - * certificate DB of the cert that is being checked - * CERTOCSPResponse *response - * the OCSP response we want to retrieve status from. - * CERTOCSPCertID *certID - * the ID we want to look for from the response. - * CERTCertificate *signerCert - * the certificate that was used to sign the OCSP response. - * must be obtained via a call to CERT_VerifyOCSPResponseSignature. - * int64 time - * The time at which we're checking the status for. - * RETURN: - * Return values are the same as those for CERT_CheckOCSPStatus - */ -extern SECStatus -CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle, - CERTOCSPResponse *response, - CERTOCSPCertID *certID, - CERTCertificate *signerCert, - int64 time); - -/* - * FUNCTION CERT_GetOCSPResponseStatus - * Returns the response status for the response passed. - * INPUTS: - * CERTOCSPResponse *response - * The response to query for status - * RETURN: - * Returns SECSuccess if the response has a successful status value. - * Otherwise it returns SECFailure and sets one of the following error - * codes via PORT_SetError - * SEC_ERROR_OCSP_MALFORMED_REQUEST - * SEC_ERROR_OCSP_SERVER_ERROR - * SEC_ERROR_OCSP_TRY_SERVER_LATER - * SEC_ERROR_OCSP_REQUEST_NEEDS_SIG - * SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST - * SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS - */ -extern SECStatus -CERT_GetOCSPResponseStatus(CERTOCSPResponse *response); - -/* - * FUNCTION CERT_CreateOCSPCertID - * Returns the OCSP certID for the certificate passed in. - * INPUTS: - * CERTCertificate *cert - * The certificate for which to create the certID for. - * int64 time - * The time at which the id is requested for. This is used - * to determine the appropriate issuer for the cert since - * the issuing CA may be an older expired certificate. - * RETURN: - * A new copy of a CERTOCSPCertID*. The memory for this certID - * should be freed by calling CERT_DestroyOCSPCertID when the - * certID is no longer necessary. - */ -extern CERTOCSPCertID* -CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time); - -/* - * FUNCTION: CERT_DestroyOCSPCertID - * Frees the memory associated with the certID passed in. - * INPUTS: - * CERTOCSPCertID* certID - * The certID that the caller no longer needs and wants to - * free the associated memory. - * RETURN: - * SECSuccess if freeing the memory was successful. Returns - * SECFailure if the memory passed in was not allocated with - * a call to CERT_CreateOCSPCertID. - */ -extern SECStatus -CERT_DestroyOCSPCertID(CERTOCSPCertID* certID); -/************************************************************************/ -SEC_END_PROTOS - -#endif /* _OCSP_H_ */ diff --git a/security/nss/lib/certhigh/ocspi.h b/security/nss/lib/certhigh/ocspi.h deleted file mode 100644 index a1c1ccb78..000000000 --- a/security/nss/lib/certhigh/ocspi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* - * ocspi.h - NSS internal interfaces to OCSP code - * - * $Id$ - */ - -#ifndef _OCSPI_H_ -#define _OCSPI_H_ - -SECStatus InitOCSPGlobal(void); - -#endif /* _OCSPI_H_ */ diff --git a/security/nss/lib/certhigh/ocspt.h b/security/nss/lib/certhigh/ocspt.h deleted file mode 100644 index 18ca8ecb6..000000000 --- a/security/nss/lib/certhigh/ocspt.h +++ /dev/null @@ -1,293 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Public header for exported OCSP types. - * - * $Id$ - */ - -#ifndef _OCSPT_H_ -#define _OCSPT_H_ - -/* - * The following are all opaque types. If someone needs to get at - * a field within, then we need to fix the API. Try very hard not - * make the type available to them. - */ -typedef struct CERTOCSPRequestStr CERTOCSPRequest; -typedef struct CERTOCSPResponseStr CERTOCSPResponse; - -/* - * XXX I think only those first two above should need to be exported, - * but until I know for certain I am leaving the rest of these here, too. - */ -typedef struct CERTOCSPCertIDStr CERTOCSPCertID; -typedef struct CERTOCSPCertStatusStr CERTOCSPCertStatus; -typedef struct CERTOCSPSingleResponseStr CERTOCSPSingleResponse; - -/* - * This interface is described in terms of an HttpClient which - * supports at least a specified set of functions. (An implementer may - * provide HttpClients with additional functionality accessible only to - * users with a particular implementation in mind.) The basic behavior - * is provided by defining a set of functions, listed in an - * SEC_HttpServerFcnStruct. If the implementor of a SpecificHttpClient - * registers his SpecificHttpClient as the default HttpClient, then his - * functions will be called by the user of an HttpClient, such as an - * OCSPChecker. - * - * The implementer of a specific HttpClient (e.g., the NSS-provided - * DefaultHttpClient), populates an SEC_HttpClientFcnStruct, uses it to - * register his client, and waits for his functions to be called. - * - * For future expandability, the SEC_HttpClientFcnStruct is defined as a - * union, with the version field acting as a selector. The proposed - * initial version of the structure is given following the definition - * of the union. The HttpClientState structure is implementation- - * dependent, and should be opaque to the user. - */ - -typedef void * SEC_HTTP_SERVER_SESSION; -typedef void * SEC_HTTP_REQUEST_SESSION; - -/* - * This function creates a SEC_HTTP_SERVER_SESSION object. The implementer of a - * specific HttpClient will allocate the necessary space, when this - * function is called, and will free it when the corresponding FreeFcn - * is called. The SEC_HTTP_SERVER_SESSION object is passed, as an opaque object, - * to subsequent calls. - * - * If the function returns SECSuccess, the returned SEC_HTTP_SERVER_SESSION - * must be cleaned up with a call to SEC_HttpServer_FreeSession, - * after processing is finished. - */ -typedef SECStatus (*SEC_HttpServer_CreateSessionFcn)( - const char *host, - PRUint16 portnum, - SEC_HTTP_SERVER_SESSION *pSession); - -/* - * This function is called to allow the implementation to attempt to keep - * the connection alive. Depending on the underlying platform, it might - * immediately return SECSuccess without having performed any operations. - * (If a connection has not been kept alive, a subsequent call to - * SEC_HttpRequest_TrySendAndReceiveFcn should reopen the connection - * automatically.) - * - * If the connection uses nonblocking I/O, this function may return - * SECWouldBlock and store a nonzero value at "pPollDesc". In that case - * the caller may wait on the poll descriptor, and should call this function - * again until SECSuccess (and a zero value at "pPollDesc") is obtained. - */ -typedef SECStatus (*SEC_HttpServer_KeepAliveSessionFcn)( - SEC_HTTP_SERVER_SESSION session, - PRPollDesc **pPollDesc); - -/* - * This function frees the client SEC_HTTP_SERVER_SESSION object, closes all - * SEC_HTTP_REQUEST_SESSIONs created for that server, discards all partial results, - * frees any memory that was allocated by the client, and invalidates any - * response pointers that might have been returned by prior server or request - * functions. - */ -typedef SECStatus (*SEC_HttpServer_FreeSessionFcn)( - SEC_HTTP_SERVER_SESSION session); - -/* - * This function creates a SEC_HTTP_REQUEST_SESSION object. The implementer of a - * specific HttpClient will allocate the necessary space, when this - * function is called, and will free it when the corresponding FreeFcn - * is called. The SEC_HTTP_REQUEST_SESSION object is passed, as an opaque object, - * to subsequent calls. - * - * An implementation that does not support the requested protocol variant - * (usually "http", but could eventually allow "https") or request method - * should return SECFailure. - * - * Timeout values may include the constants PR_INTERVAL_NO_TIMEOUT (wait - * forever) or PR_INTERVAL_NO_WAIT (nonblocking I/O). - * - * If the function returns SECSuccess, the returned SEC_HTTP_REQUEST_SESSION - * must be cleaned up with a call to SEC_HttpRequest_FreeSession, - * after processing is finished. - */ -typedef SECStatus (*SEC_HttpRequest_CreateFcn)( - SEC_HTTP_SERVER_SESSION session, - const char *http_protocol_variant, /* usually "http" */ - const char *path_and_query_string, - const char *http_request_method, - const PRIntervalTime timeout, - SEC_HTTP_REQUEST_SESSION *pRequest); - -/* - * This function sets data to be sent to the server for an HTTP request - * of http_request_method == POST. If a particular implementation - * supports it, the details for the POST request can be set by calling - * this function, prior to activating the request with TrySendAndReceiveFcn. - * - * An implementation that does not support the POST method should - * implement a SetPostDataFcn function that returns immediately. - * - * Setting http_content_type is optional, the parameter may - * by NULL or the empty string. - */ -typedef SECStatus (*SEC_HttpRequest_SetPostDataFcn)( - SEC_HTTP_REQUEST_SESSION request, - const char *http_data, - const PRUint32 http_data_len, - const char *http_content_type); - -/* - * This function sets an additional HTTP protocol request header. - * If a particular implementation supports it, one or multiple headers - * can be added to the request by calling this function once or multiple - * times, prior to activating the request with TryFcn. - * - * An implementation that does not support setting additional headers - * should implement an AddRequestHeaderFcn function that returns immediately. - */ -typedef SECStatus (*SEC_HttpRequest_AddHeaderFcn)( - SEC_HTTP_REQUEST_SESSION request, - const char *http_header_name, - const char *http_header_value); - -/* - * This function initiates or continues an HTTP request. After - * parameters have been set with the Create function and, optionally, - * modified or enhanced with the AddParams function, this call creates - * the socket connection and initiates the communication. - * - * If a timeout value of zero is specified, indicating non-blocking - * I/O, the client creates a non-blocking socket, and returns a status - * of SECWouldBlock and a non-NULL PRPollDesc if the operation is not - * complete. In that case all other return parameters are undefined. - * The caller is expected to repeat the call, possibly after using - * PRPoll to determine that a completion has occurred, until a return - * value of SECSuccess (and a NULL value for pPollDesc) or a return - * value of SECFailure (indicating failure on the network level) - * is obtained. - * - * http_response_data_len is both input and output parameter. - * If a pointer to a PRUint32 is supplied, the http client is - * expected to check the given integer value and always set an out - * value, even on failure. - * An input value of zero means, the caller will accept any response len. - * A different input value indicates the maximum response value acceptable - * to the caller. - * If data is successfully read and the size is acceptable to the caller, - * the function will return SECSuccess and set http_response_data_len to - * the size of the block returned in http_response_data. - * If the data read from the http server is larger than the acceptable - * size, the function will return SECFailure. - * http_response_data_len will be set to a value different from zero to - * indicate the reason of the failure. - * An out value of "0" means, the failure was unrelated to the - * acceptable size. - * An out value of "1" means, the result data is larger than the - * accpeptable size, but the real size is not yet known to the http client - * implementation and it stopped retrieving it, - * Any other out value combined with a return value of SECFailure - * will indicate the actual size of the server data. - * - * The caller is permitted to provide NULL values for any of the - * http_response arguments, indicating the caller is not interested in - * those values. If the caller does provide an address, the HttpClient - * stores at that address a pointer to the corresponding argument, at - * the completion of the operation. - * - * All returned pointers will be owned by the the HttpClient - * implementation and will remain valid until the call to - * SEC_HttpRequest_FreeFcn. - */ -typedef SECStatus (*SEC_HttpRequest_TrySendAndReceiveFcn)( - SEC_HTTP_REQUEST_SESSION request, - PRPollDesc **pPollDesc, - PRUint16 *http_response_code, - const char **http_response_content_type, - const char **http_response_headers, - const char **http_response_data, - PRUint32 *http_response_data_len); - -/* - * Calling CancelFcn asks for premature termination of the request. - * - * Future calls to SEC_HttpRequest_TrySendAndReceive should - * by avoided, but in this case the HttpClient implementation - * is expected to return immediately with SECFailure. - * - * After calling CancelFcn, a separate call to SEC_HttpRequest_FreeFcn - * is still necessary to free resources. - */ -typedef SECStatus (*SEC_HttpRequest_CancelFcn)( - SEC_HTTP_REQUEST_SESSION request); - -/* - * Before calling this function, it must be assured the request - * has been completed, i.e. either SEC_HttpRequest_TrySendAndReceiveFcn has - * returned SECSuccess, or the request has been canceled with - * a call to SEC_HttpRequest_CancelFcn. - * - * This function frees the client state object, closes all sockets, - * discards all partial results, frees any memory that was allocated - * by the client, and invalidates all response pointers that might - * have been returned by SEC_HttpRequest_TrySendAndReceiveFcn - */ -typedef SECStatus (*SEC_HttpRequest_FreeFcn)( - SEC_HTTP_REQUEST_SESSION request); - -typedef struct SEC_HttpClientFcnV1Struct { - SEC_HttpServer_CreateSessionFcn createSessionFcn; - SEC_HttpServer_KeepAliveSessionFcn keepAliveSessionFcn; - SEC_HttpServer_FreeSessionFcn freeSessionFcn; - SEC_HttpRequest_CreateFcn createFcn; - SEC_HttpRequest_SetPostDataFcn setPostDataFcn; - SEC_HttpRequest_AddHeaderFcn addHeaderFcn; - SEC_HttpRequest_TrySendAndReceiveFcn trySendAndReceiveFcn; - SEC_HttpRequest_CancelFcn cancelFcn; - SEC_HttpRequest_FreeFcn freeFcn; -} SEC_HttpClientFcnV1; - -typedef struct SEC_HttpClientFcnStruct { - PRInt16 version; - union { - SEC_HttpClientFcnV1 ftable1; - /* SEC_HttpClientFcnV2 ftable2; */ - /* ... */ - } fcnTable; -} SEC_HttpClientFcn; - -#endif /* _OCSPT_H_ */ diff --git a/security/nss/lib/certhigh/ocspti.h b/security/nss/lib/certhigh/ocspti.h deleted file mode 100644 index 7148c140a..000000000 --- a/security/nss/lib/certhigh/ocspti.h +++ /dev/null @@ -1,408 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Private header defining OCSP types. - * - * $Id$ - */ - -#ifndef _OCSPTI_H_ -#define _OCSPTI_H_ - -#include "ocspt.h" - -#include "certt.h" -#include "plarena.h" -#include "seccomon.h" -#include "secoidt.h" - - -/* - * Some notes about naming conventions... - * - * The public data types all start with "CERTOCSP" (e.g. CERTOCSPRequest). - * (Even the public types are opaque, however. Only their names are - * "exported".) - * - * Internal-only data types drop the "CERT" prefix and use only the - * lower-case "ocsp" (e.g. ocspTBSRequest), for brevity sake. - * - * In either case, the base/suffix of the type name usually matches the - * name as defined in the OCSP specification. The exceptions to this are: - * - When there is overlap between the "OCSP" or "ocsp" prefix and - * the name used in the standard. That is, you cannot strip off the - * "CERTOCSP" or "ocsp" prefix and necessarily get the name of the - * type as it is defined in the standard; the "real" name will be - * *either* "OCSPSuffix" or just "Suffix". - * - When the name in the standard was a little too generic. (e.g. The - * standard defines "Request" but we call it a "SingleRequest".) - * In this case a comment above the type definition calls attention - * to the difference. - * - * The definitions laid out in this header file are intended to follow - * the same order as the definitions in the OCSP specification itself. - * With the OCSP standard in hand, you should be able to move through - * this file and follow along. To future modifiers of this file: please - * try to keep it that way. The only exceptions are the few cases where - * we need to define a type before it is referenced (e.g. enumerations), - * whereas in the OCSP specification these are usually defined the other - * way around (reference before definition). - */ - - -/* - * Forward-declarations of internal-only data structures. - * - * These are in alphabetical order (case-insensitive); please keep it that way! - */ -typedef struct ocspBasicOCSPResponseStr ocspBasicOCSPResponse; -typedef struct ocspCertStatusStr ocspCertStatus; -typedef struct ocspResponderIDStr ocspResponderID; -typedef struct ocspResponseBytesStr ocspResponseBytes; -typedef struct ocspResponseDataStr ocspResponseData; -typedef struct ocspRevokedInfoStr ocspRevokedInfo; -typedef struct ocspServiceLocatorStr ocspServiceLocator; -typedef struct ocspSignatureStr ocspSignature; -typedef struct ocspSingleRequestStr ocspSingleRequest; -typedef struct ocspSingleResponseStr ocspSingleResponse; -typedef struct ocspTBSRequestStr ocspTBSRequest; - - -/* - * An OCSPRequest; this is what is sent (encoded) to an OCSP responder. - */ -struct CERTOCSPRequestStr { - PRArenaPool *arena; /* local; not part of encoding */ - ocspTBSRequest *tbsRequest; - ocspSignature *optionalSignature; -}; - -/* - * A TBSRequest; when an OCSPRequest is signed, the encoding of this - * is what the signature is actually applied to. ("TBS" == To Be Signed) - * Whether signed or not, however, this structure will be present, and - * is the "meat" of the OCSPRequest. - * - * Note that the "requestorName" field cannot be encoded/decoded in the - * same pass as the entire request -- it needs to be handled with a special - * call to convert to/from our internal form of a GeneralName. Thus the - * "derRequestorName" field, which is the actual DER-encoded bytes. - * - * The "extensionHandle" field is used on creation only; it holds - * in-progress extensions as they are optionally added to the request. - */ -struct ocspTBSRequestStr { - SECItem version; /* an INTEGER */ - SECItem *derRequestorName; /* encoded GeneralName; see above */ - CERTGeneralNameList *requestorName; /* local; not part of encoding */ - ocspSingleRequest **requestList; - CERTCertExtension **requestExtensions; - void *extensionHandle; /* local; not part of encoding */ -}; - -/* - * This is the actual signature information for an OCSPRequest (applied to - * the TBSRequest structure) or for a BasicOCSPResponse (applied to a - * ResponseData structure). - * - * Note that the "signature" field itself is a BIT STRING; operations on - * it need to keep that in mind, converting the length to bytes as needed - * and back again afterward (so that the length is usually expressing bits). - * - * The "cert" field is the signer's certificate. In the case of a received - * signature, it will be filled in when the signature is verified. In the - * case of a created signature, it is filled in on creation and will be the - * cert used to create the signature when the signing-and-encoding occurs, - * as well as the cert (and its chain) to fill in derCerts if requested. - * - * The extra fields cache information about the signature after we have - * attempted a verification. "wasChecked", if true, means the signature - * has been checked against the appropriate data and thus that "status" - * contains the result of that verification. If "status" is not SECSuccess, - * "failureReason" is a copy of the error code that was set at the time; - * presumably it tells why the signature verification failed. - */ -struct ocspSignatureStr { - SECAlgorithmID signatureAlgorithm; - SECItem signature; /* a BIT STRING */ - SECItem **derCerts; /* a SEQUENCE OF Certificate */ - CERTCertificate *cert; /* local; not part of encoding */ - PRBool wasChecked; /* local; not part of encoding */ - SECStatus status; /* local; not part of encoding */ - int failureReason; /* local; not part of encoding */ -}; - -/* - * An OCSPRequest contains a SEQUENCE OF these, one for each certificate - * whose status is being checked. - * - * Note that in the OCSP specification this is just called "Request", - * but since that seemed confusing (vs. an OCSPRequest) and to be more - * consistent with the parallel type "SingleResponse", I called it a - * "SingleRequest". - * - * XXX figure out how to get rid of that arena -- there must be a way - */ -struct ocspSingleRequestStr { - PRArenaPool *arena; /* just a copy of the response arena, - * needed here for extension handling - * routines, on creation only */ - CERTOCSPCertID *reqCert; - CERTCertExtension **singleRequestExtensions; -}; - -/* - * A CertID is the means of identifying a certificate, used both in requests - * and in responses. - * - * When in a SingleRequest it specifies the certificate to be checked. - * When in a SingleResponse it is the cert whose status is being given. - */ -struct CERTOCSPCertIDStr { - SECAlgorithmID hashAlgorithm; - SECItem issuerNameHash; /* an OCTET STRING */ - SECItem issuerKeyHash; /* an OCTET STRING */ - SECItem serialNumber; /* an INTEGER */ - SECItem issuerSHA1NameHash; /* keep other hashes around when */ - SECItem issuerMD5NameHash; /* we have them */ - SECItem issuerMD2NameHash; - SECItem issuerSHA1KeyHash; /* keep other hashes around when */ - SECItem issuerMD5KeyHash; /* we have them */ - SECItem issuerMD2KeyHash; - PRArenaPool *poolp; -}; - -/* - * This describes the value of the responseStatus field in an OCSPResponse. - * The corresponding ASN.1 definition is: - * - * OCSPResponseStatus ::= ENUMERATED { - * successful (0), --Response has valid confirmations - * malformedRequest (1), --Illegal confirmation request - * internalError (2), --Internal error in issuer - * tryLater (3), --Try again later - * --(4) is not used - * sigRequired (5), --Must sign the request - * unauthorized (6), --Request unauthorized - * } - */ -typedef enum { - ocspResponse_successful = 0, - ocspResponse_malformedRequest = 1, - ocspResponse_internalError = 2, - ocspResponse_tryLater = 3, - ocspResponse_unused = 4, - ocspResponse_sigRequired = 5, - ocspResponse_unauthorized = 6, - ocspResponse_other /* unknown/unrecognized value */ -} ocspResponseStatus; - -/* - * An OCSPResponse is what is sent (encoded) by an OCSP responder. - * - * The field "responseStatus" is the ASN.1 encoded value; the field - * "statusValue" is simply that same value translated into our local - * type ocspResponseStatus. - */ -struct CERTOCSPResponseStr { - PRArenaPool *arena; /* local; not part of encoding */ - SECItem responseStatus; /* an ENUMERATED, see above */ - ocspResponseStatus statusValue; /* local; not part of encoding */ - ocspResponseBytes *responseBytes; /* only when status is successful */ -}; - -/* - * A ResponseBytes (despite appearances) is what contains the meat - * of a successful response -- but still in encoded form. The type - * given as "responseType" tells you how to decode the string. - * - * We look at the OID and translate it into our local OID representation - * "responseTypeTag", and use that value to tell us how to decode the - * actual response itself. For now the only kind of OCSP response we - * know about is a BasicOCSPResponse. However, the intention in the - * OCSP specification is to allow for other response types, so we are - * building in that flexibility from the start and thus put a pointer - * to that data structure inside of a union. Whenever OCSP adds more - * response types, just add them to the union. - */ -struct ocspResponseBytesStr { - SECItem responseType; /* an OBJECT IDENTIFIER */ - SECOidTag responseTypeTag; /* local; not part of encoding */ - SECItem response; /* an OCTET STRING */ - union { - ocspBasicOCSPResponse *basic; /* when type is id-pkix-ocsp-basic */ - } decodedResponse; /* local; not part of encoding */ -}; - -/* - * A BasicOCSPResponse -- when the responseType in a ResponseBytes is - * id-pkix-ocsp-basic, the "response" OCTET STRING above is the DER - * encoding of one of these. - * - * Note that in the OCSP specification, the signature fields are not - * part of a separate sub-structure. But since they are the same fields - * as we define for the signature in a request, it made sense to share - * the C data structure here and in some shared code to operate on them. - */ -struct ocspBasicOCSPResponseStr { - ocspResponseData *tbsResponseData; /* "tbs" == To Be Signed */ - ocspSignature responseSignature; -}; - -/* - * A ResponseData is the part of a BasicOCSPResponse that is signed - * (after it is DER encoded). It contains the real details of the response - * (a per-certificate status). - */ -struct ocspResponseDataStr { - SECItem version; /* an INTEGER */ - SECItem derResponderID; - ocspResponderID *responderID; /* local; not part of encoding */ - SECItem producedAt; /* a GeneralizedTime */ - CERTOCSPSingleResponse **responses; - CERTCertExtension **responseExtensions; -}; - -/* - * A ResponderID identifies the responder -- or more correctly, the - * signer of the response. The ASN.1 definition of a ResponderID is: - * - * ResponderID ::= CHOICE { - * byName [1] EXPLICIT Name, - * byKey [2] EXPLICIT KeyHash } - * - * Because it is CHOICE, the type of identification used and the - * identification itself are actually encoded together. To represent - * this same information internally, we explicitly define a type and - * save it, along with the value, into a data structure. - */ - -typedef enum { - ocspResponderID_byName, - ocspResponderID_byKey, - ocspResponderID_other /* unknown kind of responderID */ -} ocspResponderIDType; - -struct ocspResponderIDStr { - ocspResponderIDType responderIDType;/* local; not part of encoding */ - union { - CERTName name; /* when ocspResponderID_byName */ - SECItem keyHash; /* when ocspResponderID_byKey */ - SECItem other; /* when ocspResponderID_other */ - } responderIDValue; -}; - -/* - * The ResponseData in a BasicOCSPResponse contains a SEQUENCE OF - * SingleResponse -- one for each certificate whose status is being supplied. - * - * XXX figure out how to get rid of that arena -- there must be a way - */ -struct CERTOCSPSingleResponseStr { - PRArenaPool *arena; /* just a copy of the response arena, - * needed here for extension handling - * routines, on creation only */ - CERTOCSPCertID *certID; - SECItem derCertStatus; - ocspCertStatus *certStatus; /* local; not part of encoding */ - SECItem thisUpdate; /* a GeneralizedTime */ - SECItem *nextUpdate; /* a GeneralizedTime */ - CERTCertExtension **singleExtensions; -}; - -/* - * A CertStatus is the actual per-certificate status. Its ASN.1 definition: - * - * CertStatus ::= CHOICE { - * good [0] IMPLICIT NULL, - * revoked [1] IMPLICIT RevokedInfo, - * unknown [2] IMPLICIT UnknownInfo } - * - * (where for now UnknownInfo is defined to be NULL but in the - * future may be replaced with an enumeration). - * - * Because it is CHOICE, the status value and its associated information - * (if any) are actually encoded together. To represent this same - * information internally, we explicitly define a type and save it, - * along with the value, into a data structure. - */ - -typedef enum { - ocspCertStatus_good, /* cert is not revoked */ - ocspCertStatus_revoked, /* cert is revoked */ - ocspCertStatus_unknown, /* cert was unknown to the responder */ - ocspCertStatus_other /* status was not an expected value */ -} ocspCertStatusType; - -/* - * This is the actual per-certificate status. - * - * The "goodInfo" and "unknownInfo" items are only place-holders for a NULL. - * (Though someday OCSP may replace UnknownInfo with an enumeration that - * gives more detailed information.) - */ -struct ocspCertStatusStr { - ocspCertStatusType certStatusType; /* local; not part of encoding */ - union { - SECItem *goodInfo; /* when ocspCertStatus_good */ - ocspRevokedInfo *revokedInfo; /* when ocspCertStatus_revoked */ - SECItem *unknownInfo; /* when ocspCertStatus_unknown */ - SECItem *otherInfo; /* when ocspCertStatus_other */ - } certStatusInfo; -}; - -/* - * A RevokedInfo gives information about a revoked certificate -- when it - * was revoked and why. - */ -struct ocspRevokedInfoStr { - SECItem revocationTime; /* a GeneralizedTime */ - SECItem *revocationReason; /* a CRLReason; ignored for now */ -}; - -/* - * ServiceLocator can be included as one of the singleRequestExtensions. - * When added, it specifies the (name of the) issuer of the cert being - * checked, and optionally the value of the AuthorityInfoAccess extension - * if the cert has one. - */ -struct ocspServiceLocatorStr { - CERTName *issuer; - SECItem locator; /* DER encoded authInfoAccess extension from cert */ -}; - -#endif /* _OCSPTI_H_ */ diff --git a/security/nss/lib/certhigh/xcrldist.c b/security/nss/lib/certhigh/xcrldist.c deleted file mode 100644 index 07b226856..000000000 --- a/security/nss/lib/certhigh/xcrldist.c +++ /dev/null @@ -1,233 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Code for dealing with x.509 v3 CRL Distribution Point extension. - */ -#include "genname.h" -#include "certt.h" -#include "secerr.h" - -extern void PrepareBitStringForEncoding (SECItem *bitMap, SECItem *value); - -static const SEC_ASN1Template FullNameTemplate[] = { - {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, - offsetof (CRLDistributionPoint,derFullName), CERT_GeneralNamesTemplate} -}; - -static const SEC_ASN1Template RelativeNameTemplate[] = { - {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, - offsetof (CRLDistributionPoint,distPoint.relativeName), CERT_RDNTemplate} -}; - -static const SEC_ASN1Template CRLDistributionPointTemplate[] = { - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | - SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0, - offsetof(CRLDistributionPoint,derDistPoint), SEC_AnyTemplate}, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, - offsetof(CRLDistributionPoint,bitsmap), SEC_BitStringTemplate}, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | - SEC_ASN1_CONSTRUCTED | 2, - offsetof(CRLDistributionPoint, derCrlIssuer), CERT_GeneralNamesTemplate}, - { 0 } -}; - -const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = { - {SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate} -}; - -SECStatus -CERT_EncodeCRLDistributionPoints (PRArenaPool *arena, CERTCrlDistributionPoints *value, - SECItem *derValue) -{ - CRLDistributionPoint **pointList, *point; - PRArenaPool *ourPool = NULL; - SECStatus rv = SECSuccess; - - PORT_Assert (derValue); - PORT_Assert (value && value->distPoints); - - do { - ourPool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); - if (ourPool == NULL) { - rv = SECFailure; - break; - } - - pointList = value->distPoints; - while (*pointList) { - point = *pointList; - point->derFullName = NULL; - point->derDistPoint.data = NULL; - - if (point->distPointType == generalName) { - point->derFullName = cert_EncodeGeneralNames - (ourPool, point->distPoint.fullName); - - if (point->derFullName) { - rv = (SEC_ASN1EncodeItem (ourPool, &point->derDistPoint, - point, FullNameTemplate) == NULL) ? SECFailure : SECSuccess; - } else { - rv = SECFailure; - } - } - else if (point->distPointType == relativeDistinguishedName) { - if (SEC_ASN1EncodeItem - (ourPool, &point->derDistPoint, - point, RelativeNameTemplate) == NULL) - rv = SECFailure; - } - /* distributionPointName is omitted */ - else if (point->distPointType != 0) { - PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); - rv = SECFailure; - } - if (rv != SECSuccess) - break; - - if (point->reasons.data) - PrepareBitStringForEncoding (&point->bitsmap, &point->reasons); - - if (point->crlIssuer) { - point->derCrlIssuer = cert_EncodeGeneralNames - (ourPool, point->crlIssuer); - if (!point->crlIssuer) - break; - } - - ++pointList; - } - if (rv != SECSuccess) - break; - if (SEC_ASN1EncodeItem - (arena, derValue, value, CERTCRLDistributionPointsTemplate) == NULL) { - rv = SECFailure; - break; - } - } while (0); - PORT_FreeArena (ourPool, PR_FALSE); - return (rv); -} - -CERTCrlDistributionPoints * -CERT_DecodeCRLDistributionPoints (PRArenaPool *arena, SECItem *encodedValue) -{ - CERTCrlDistributionPoints *value = NULL; - CRLDistributionPoint **pointList, *point; - SECStatus rv; - SECItem newEncodedValue; - - PORT_Assert (arena); - do { - value = (CERTCrlDistributionPoints*)PORT_ArenaZAlloc (arena, sizeof (*value)); - if (value == NULL) { - rv = SECFailure; - break; - } - - /* copy the DER into the arena, since Quick DER returns data that points - into the DER input, which may get freed by the caller */ - rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); - if ( rv != SECSuccess ) { - break; - } - - rv = SEC_QuickDERDecodeItem - (arena, &value->distPoints, CERTCRLDistributionPointsTemplate, - &newEncodedValue); - if (rv != SECSuccess) - break; - - pointList = value->distPoints; - while (*pointList) { - point = *pointList; - - /* get the data if the distributionPointName is not omitted */ - if (point->derDistPoint.data != NULL) { - point->distPointType = (DistributionPointTypes) - ((point->derDistPoint.data[0] & 0x1f) +1); - if (point->distPointType == generalName) { - SECItem innerDER; - - innerDER.data = NULL; - rv = SEC_QuickDERDecodeItem - (arena, point, FullNameTemplate, &(point->derDistPoint)); - if (rv != SECSuccess) - break; - point->distPoint.fullName = cert_DecodeGeneralNames - (arena, point->derFullName); - - if (!point->distPoint.fullName) - break; - } - else if ( relativeDistinguishedName) { - rv = SEC_QuickDERDecodeItem - (arena, point, RelativeNameTemplate, &(point->derDistPoint)); - if (rv != SECSuccess) - break; - } - else { - PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); - break; - } - } - - /* Get the reason code if it's not omitted in the encoding */ - if (point->bitsmap.data != NULL) { - point->reasons.data = (unsigned char*) PORT_ArenaAlloc - (arena, (point->bitsmap.len + 7) >> 3); - if (!point->reasons.data) { - rv = SECFailure; - break; - } - PORT_Memcpy (point->reasons.data, point->bitsmap.data, - point->reasons.len = ((point->bitsmap.len + 7) >> 3)); - } - - /* Get the crl issuer name if it's not omitted in the encoding */ - if (point->derCrlIssuer != NULL) { - point->crlIssuer = cert_DecodeGeneralNames - (arena, point->derCrlIssuer); - - if (!point->crlIssuer) - break; - } - ++pointList; - } - } while (0); - return (rv == SECSuccess ? value : NULL); -} |