/* * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * ocspResponse.h - OCSP Response class */ #ifndef _OCSP_RESPONSE_H_ #define _OCSP_RESPONSE_H_ #include <security_ocspd/ocspExtensions.h> #include <Security/ocspTemplates.h> #include <Security/certextensions.h> #include <Security/SecAsn1Coder.h> #include <CoreFoundation/CoreFoundation.h> /* used to indicate "I don't know the CRLReason" */ #define CrlReason_NONE ((CE_CrlReason)-1) /* * CertIDs can be represented differently by two peers even though they refer to * the same cert. Client can use SHA1 hash and server can use MD5, for example. * So all of our code which creates a CertID based on known, existing subject and * issuer certs uses one of these "smart" certIDs which can encode itself and also * compare against any form of existing SecAsn1OCSPCertID. */ class OCSPClientCertID { NOCOPY(OCSPClientCertID); public: /* * Basic constructor given issuer's public key and name, and subject's * serial number. */ OCSPClientCertID( const CSSM_DATA &issuerName, const CSSM_DATA &issuerPubKey, const CSSM_DATA &subjectSerial); ~OCSPClientCertID(); /* * DER encode. */ const CSSM_DATA *encode(); /* * Does this object refer to the same cert as specified SecAsn1OCSPCertID? * This is the main purpose of this class's existence; this function works * even if specified SecAsn1OCSPCertID uses a different hash algorithm * than we do, since we keep copies of our basic components. * * Returns true if compare successful. */ bool compareToExist( const SecAsn1OCSPCertID &exist); /* * Convenience function, like compareToExist, with a raw encoded CertID. */ bool compareToExist( const CSSM_DATA &exist); private: CSSM_DATA mIssuerName; CSSM_DATA mIssuerPubKey; CSSM_DATA mSubjectSerial; CSSM_DATA mEncoded; }; /* * Object representing one SecAsn1OCSPSingleResponse, i.e., the portion of * an OCSP response associated with a single CertID. These are created and * vended solely by an OCSPResponse object. The client which gets them from * an OCSPResponse (via singleResponse()) must delete the object when finished * with it. */ class OCSPSingleResponse { NOCOPY(OCSPSingleResponse); public: /* only OCSPResponse creates these */ ~OCSPSingleResponse(); friend class OCSPResponse; protected: OCSPSingleResponse( SecAsn1OCSPSingleResponse *resp); public: SecAsn1OCSPCertStatusTag certStatus() { return mCertStatus; } CFAbsoluteTime thisUpdate() { return mThisUpdate; } CFAbsoluteTime nextUpdate() { return mNextUpdate; } CFAbsoluteTime revokedTime() { return mRevokedTime; } CE_CrlReason crlReason() { return mCrlReason; } /* Extension accessors - all are optional */ /* CRL Reference */ const CSSM_DATA *crlUrl(); const CSSM_DATA *crlNum(); CFAbsoluteTime crlTime(); /* may be NULL_TIME */ /* archive cutoff */ CFAbsoluteTime archiveCutoff(); /* service locator not implemented yet */ private: SecAsn1CoderRef mCoder; SecAsn1OCSPCertStatusTag mCertStatus; CFAbsoluteTime mThisUpdate; CFAbsoluteTime mNextUpdate; /* may be NULL_TIME */ CFAbsoluteTime mRevokedTime; /* != NULL_TIME for CS_Revoked */ CE_CrlReason mCrlReason; OCSPExtensions *mExtensions; }; /* * OCSPResponse maintains its own temporal validity status based on the values of * all of the enclosed SingleResponses' thisUpdate and (optional) nextUpdate * fields, in addition to a default time-to-live (TTL) value passed to * OCSPResponse's constructor. * * First, all of the thisUpdate fields are checked during OCSPResponse's constructor. * if any of these are later than the current time, the entire response is considered * invalid and the constructor throws a CssmError(CSSMERR_APPLETP_OCSP_BAD_RESPONSE). * Subsequent to construction, all thisUpdate fields are ignored. * * The NextUpdate times are handled as follows. * * 1. An OCSPResponse's latestNextUpdate is defined as the latest of all of the * nextUpdate fields in its SingleResponses. This is evaluated during construction. * * 2. An OCSPResponse's latestNextUpdate is NULL_TIME if none of its SingleResponses * contain any nextUpdate (this field is in fact optional). * * 3. The caller of OCSPResponse's constructor passes in a default time-to-live * (TTL) in seconds; call this defaultTTL. Call the time at which the * constructor is called, PLUS defaultTTL, "defaultExpire". * * -- If the OCSPResponse's latestNextUpdate is NULL_TIME then expireTime() returns * defaultExpire. * * -- Otherwise, expireTime() returns the lesser of (latestNextUpdate, * defaultExpire). * * Note that this mechanism is used by both the TP's in-core cache and ocspd's * on-disk cache; the two have different default TTLs values but the mechanism * for calcuating expireTime() is identical. */ class OCSPResponse { NOCOPY(OCSPResponse) public: /* only constructor, from DER encoded data */ OCSPResponse( const CSSM_DATA &resp, CFTimeInterval defaultTTL); // default time-to-live in seconds ~OCSPResponse(); /* * Info obtained during decode (which is done immediately during constructor) */ SecAsn1OCSPResponseStatus responseStatus(); const CSSM_DATA *nonce(); /* NULL means not present */ CFAbsoluteTime producedAt(); /* should always work */ CSSM_RETURN sigStatus(); uint32 numSignerCerts(); const CSSM_DATA *signerCert(uint32 dex); /* * Obtain a OCSPSingleResponse for a given CertID. */ OCSPSingleResponse *singleResponseFor(OCSPClientCertID &certID); OCSPSingleResponse *singleResponseFor(const CSSM_DATA &matchCertID); CFAbsoluteTime expireTime() { return mExpireTime; } /* * Access to decoded data. */ const SecAsn1OCSPResponseData &responseData() { return mResponseData; } const SecAsn1OCSPBasicResponse &basicResponse() { return mBasicResponse; } const SecAsn1OCSPResponderID &responderID() { return mResponderId; } SecAsn1OCSPResponderIDTag responderIDTag() { return mResponderIdTag; } const CSSM_DATA *encResponderName(); private: bool calculateValidity(CFTimeInterval defaultTTL); SecAsn1CoderRef mCoder; CFAbsoluteTime mLatestNextUpdate; CFAbsoluteTime mExpireTime; CSSM_DATA mEncResponderName; // encoded ResponderId.byName, // if responder is in that format, // lazily evaluated /* * Fields we decode - all in mCoder's memory space */ SecAsn1OCSPResponse mTopResp; SecAsn1OCSPBasicResponse mBasicResponse; SecAsn1OCSPResponseData mResponseData; SecAsn1OCSPResponderID mResponderId; // we have to decode SecAsn1OCSPResponderIDTag mResponderIdTag; // IDs previous field OCSPExtensions *mExtensions; }; #endif /* _OCSP_RESPONSE_H_ */