/*
 * Copyright (c) 2003-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@
 *
 * ocspTemplates.h -  ASN1 templates OCSP requests and responses.
 */

#ifndef	_OCSP_TEMPLATES_H_
#define _OCSP_TEMPLATES_H_

#include <Security/secasn1t.h>
#include <Security/x509defs.h>		/* CSSM_X509_ALGORITHM_IDENTIFIER */
#include <Security/X509Templates.h> /* NSS_CertExtension */
#include <Security/nameTemplates.h> /* NSS_GeneralName and support */

#ifdef  __cplusplus
extern "C" {
#endif

#pragma mark ----- OCSP Request -----

/*
 * CertID          ::=     SEQUENCE {
 *		hashAlgorithm		AlgorithmIdentifier,
 *		issuerNameHash		OCTET STRING, -- Hash of Issuer's DN
 *		issuerKeyHash		OCTET STRING, -- Hash of Issuers public key
 *		serialNumber		CertificateSerialNumber }   -- i.e., INTEGER
 */
typedef struct {
	CSSM_X509_ALGORITHM_IDENTIFIER		algId;
	CSSM_DATA							issuerNameHash;
	CSSM_DATA							issuerPubKeyHash;
	CSSM_DATA							serialNumber;
} SecAsn1OCSPCertID;

extern const SecAsn1Template kSecAsn1OCSPCertIDTemplate[];
 
/*
 * Request         ::=     SEQUENCE {
 *		reqCert                     CertID,
 *		singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }  
 */
typedef struct {
	SecAsn1OCSPCertID					reqCert;
    NSS_CertExtension 					**extensions;		// optional	
} SecAsn1OCSPRequest;

extern const SecAsn1Template kSecAsn1OCSPRequestTemplate[];

/*
 * Signature       ::=     SEQUENCE {
 *		signatureAlgorithm      AlgorithmIdentifier,
 *		signature               BIT STRING,
 *		certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
 *
 * Since we wish to avoid knowing anything about the details of the certs, 
 * we declare them here as ASN_ANY, get/set as raw data, and leave it to 
 * the CL to parse them.
 */
typedef struct {
	CSSM_X509_ALGORITHM_IDENTIFIER		algId;
	CSSM_DATA							sig;		// length in BITS
	CSSM_DATA							**certs;	// OPTIONAL
} SecAsn1OCSPSignature;

extern const SecAsn1Template kSecAsn1OCSPSignatureTemplate[];

/* 
 * TBSRequest      ::=     SEQUENCE {
 *		version             [0]     EXPLICIT Version DEFAULT v1,
 *		requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
 *		requestList                 SEQUENCE OF Request,
 *		requestExtensions   [2]     EXPLICIT Extensions OPTIONAL } 
 */
typedef struct {
	CSSM_DATA							*version;				// OPTIONAL
	NSS_GeneralName						*requestorName;			// OPTIONAL
	SecAsn1OCSPRequest					**requestList;
    NSS_CertExtension 					**requestExtensions;	// OPTIONAL
} SecAsn1OCSPTbsRequest;

extern const SecAsn1Template kSecAsn1OCSPTbsRequestTemplate[];

/* 
 * OCSPRequest     ::=     SEQUENCE {
 *		tbsRequest                  TBSRequest,
 *		optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
 */
typedef struct {
	SecAsn1OCSPTbsRequest				tbsRequest;
	SecAsn1OCSPSignature				*signature;			// OPTIONAL
} SecAsn1OCSPSignedRequest;

extern const SecAsn1Template kSecAsn1OCSPSignedRequestTemplate[];

#pragma mark ----- OCSP Response -----

/*
 * CertStatus ::= CHOICE {
 *		good        [0]     IMPLICIT NULL,
 *		revoked     [1]     IMPLICIT RevokedInfo,
 *		unknown     [2]     IMPLICIT UnknownInfo }
 *
 * RevokedInfo ::= SEQUENCE {
 *		revocationTime              GeneralizedTime,
 *		revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
 *
 * UnknownInfo ::= NULL -- this can be replaced with an enumeration
 *
 * See <Security/certextensions.h> for enum values of CE_CrlReason.
 */
typedef struct {
	CSSM_DATA					revocationTime;
	CSSM_DATA					*revocationReason;		// OPTIONAL, CE_CrlReason
} SecAsn1OCSPRevokedInfo;

typedef union {
	SecAsn1OCSPRevokedInfo		*revokedInfo;
	CSSM_DATA					*nullData;
} SecAsn1OCSPCertStatus;

typedef enum {
	CS_Good = 0,
	CS_Revoked = 1,
	CS_Unknown = 2,
	CS_NotParsed = 0xff		/* Not in protocol: means value not parsed or seen */
} SecAsn1OCSPCertStatusTag;

extern const SecAsn1Template kSecAsn1OCSPRevokedInfoTemplate[];

/* 
 * Encode/decode CertStatus separately using one of these  hree templates. 
 * The result goes into SecAsn1OCSPSingleResponse.certStatus on encode. 
 */
extern const SecAsn1Template kSecAsn1OCSPCertStatusGoodTemplate[];
extern const SecAsn1Template kSecAsn1OCSPCertStatusRevokedTemplate[];
extern const SecAsn1Template kSecAsn1OCSPCertStatusUnknownTemplate[];

/* 
 * SingleResponse ::= SEQUENCE {
 *		certID                       CertID,
 *		certStatus                   CertStatus,
 *		thisUpdate                   GeneralizedTime,
 *		nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
 *		singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
 */
typedef struct {
	SecAsn1OCSPCertID			certID;
	CSSM_DATA					certStatus;				// ASN_ANY here
	CSSM_DATA					thisUpdate;				// GeneralizedTime
	CSSM_DATA					*nextUpdate;			// GeneralizedTime, OPTIONAL
    NSS_CertExtension 			**singleExtensions;		// OPTIONAL
} SecAsn1OCSPSingleResponse;

extern const SecAsn1Template kSecAsn1OCSPSingleResponseTemplate[];

/*
 * ResponderID ::= CHOICE {
 *     byName               EXPLICIT [1] Name,
 *     byKey                EXPLICIT [2] KeyHash }
 *
 * Since our ASN.1 encoder/decoder can't handle CHOICEs very well, we encode
 * this separately using one of the following two templates. On encode the
 * result if this step of the encode goes into SecAsn1OCSPResponseData.responderID,
 * where it's treated as an ANY_ANY when encoding that struct. The reverse happens
 * on decode. 
 */
typedef union {
	NSS_Name					byName;
	CSSM_DATA					byKey;		// key hash in OCTET STRING
} SecAsn1OCSPResponderID;

typedef enum {
	RIT_Name	= 1,
	RIT_Key		= 2
} SecAsn1OCSPResponderIDTag;

extern const SecAsn1Template kSecAsn1OCSPResponderIDAsNameTemplate[];
extern const SecAsn1Template kSecAsn1OCSPResponderIDAsKeyTemplate[];

/* 
 * ResponseData ::= SEQUENCE {
 *		version              [0] EXPLICIT Version DEFAULT v1,
 *		responderID              ResponderID,
 *		producedAt               GeneralizedTime,
 *		responses                SEQUENCE OF SingleResponse,
 *		responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
 */
typedef struct {
	CSSM_DATA					*version;		// OPTIONAL
	CSSM_DATA					responderID;	// ASN_ANY here, decode/encode separately
	CSSM_DATA					producedAt;		// GeneralizedTime
	SecAsn1OCSPSingleResponse   **responses;
    NSS_CertExtension 			**responseExtensions;	// OPTIONAL
} SecAsn1OCSPResponseData;

extern const SecAsn1Template kSecAsn1OCSPResponseDataTemplate[];

/* 
 * BasicOCSPResponse       ::= SEQUENCE {
 *		tbsResponseData      ResponseData,
 *		signatureAlgorithm   AlgorithmIdentifier,
 *		signature            BIT STRING,
 *		certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
 *
 * Since we ALWAYS encode the tbsResponseData in preparation for signing,
 * we declare it as a raw ASN_ANY in the BasicOCSPResponse.
 *
 * Certs are likewise ASN_ANY since we use the CL to parse and create them. 
 */
typedef struct {
	CSSM_DATA						tbsResponseData;
	CSSM_X509_ALGORITHM_IDENTIFIER	algId;
	CSSM_DATA						sig;		// length in BITS
	CSSM_DATA						**certs;	// optional
} SecAsn1OCSPBasicResponse;

extern const SecAsn1Template kSecAsn1OCSPBasicResponseTemplate[];

/*
 * ResponseBytes ::=       SEQUENCE {
 *		responseType   OBJECT IDENTIFIER,
 *		response       OCTET STRING }
 *
 * The contents of response are actually an encoded SecAsn1OCSPBasicResponse (at 
 * least until another response type is defined). 
 */
typedef struct {
	CSSM_OID					responseType;
	CSSM_DATA					response;
} SecAsn1OCSPResponseBytes;

extern const SecAsn1Template kSecAsn1OCSPResponseBytesTemplate[];

/* 
 * OCSPResponse ::= SEQUENCE {
 *		responseStatus         OCSPResponseStatus,		-- an ENUM
 *		responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
 */
typedef struct {
	CSSM_DATA					responseStatus;		// see enum below
	SecAsn1OCSPResponseBytes	*responseBytes;		// optional
} SecAsn1OCSPResponse;

extern const SecAsn1Template kSecAsn1OCSPResponseTemplate[];

typedef enum {
	RS_Success = 0,
	RS_MalformedRequest = 1,
	RS_InternalError = 2,
	RS_TryLater = 3,
	RS_Unused = 4,
	RS_SigRequired = 5,
	RS_Unauthorized = 6
} SecAsn1OCSPResponseStatus;

/* 
 * This is not part of the OCSP protocol; it's used in the communication between
 * the Apple X.509 TP module and the ocspd server.
 *
 * OCSPDRequest ::= SEQUENCE {
 *		cacheWriteDisable :: = EXPLICIT [0] BOOL OPTIONAL;	-- cache write disable
 *															--  default FALSE
 *		cacheWriteDisable :: = EXPLICIT [1] BOOL OPTIONAL;	-- cache read disable
 *															--  default FALSE
 *		certID		::= OCTET STRING;						-- for cache lookup
 *		ocspReq		::= EXPLICIT [2] OCTET STRING OPTIONAL;	-- for net fetch
 *		localResp	::= EXPLICIT [3] IA5String OPTIONAL;	-- for local responder
 *		urls		::= EXPLICIT [4] SEQUENCE of IA5String OPTIONAL;
 *															-- for normal net fetch
 * };
 */

#define OCSPD_REQUEST_VERS	0

typedef struct {
	CSSM_DATA			*cacheWriteDisable;
	CSSM_DATA			*cacheReadDisable;
	CSSM_DATA			certID;				// DER encoded SecAsn1OCSPCertID
	CSSM_DATA			*ocspReq;			// DER encoded SecAsn1OCSPSignedRequest
	CSSM_DATA			*localRespURI;		// local responder URI
	CSSM_DATA			**urls;				// normal URIs
	
} SecAsn1OCSPDRequest;

/* 
 * And this is a sequence of them, packaged up and sent to ocspd in one RPC.
 */
typedef struct {
	CSSM_DATA			version;			// OCSPD_REQUEST_VERS
	SecAsn1OCSPDRequest	**requests;
} SecAsn1OCSPDRequests;

extern const SecAsn1Template kSecAsn1OCSPDRequestTemplate[];
extern const SecAsn1Template kSecAsn1OCSPDRequestsTemplate[];

/* 
 * Unordered set of replies from ocsdp; they map back to individual
 * SecAsn1OCSPDRequests by the encoded certID (which is obtained from the 
 * SecAsn1OCSPDRequest, NOT from the OCSP response).
 */
typedef struct {
	CSSM_DATA			certID;			// DER encoded SecAsn1OCSPCertID
	CSSM_DATA			ocspResp;		// DER encoded SecAsn1OCSPResponse
} SecAsn1OCSPDReply;

#define OCSPD_REPLY_VERS	0

typedef struct {
	CSSM_DATA			version;			// OCSPD_REPLY_VERS
	SecAsn1OCSPDReply	**replies; 
} SecAsn1OCSPReplies;

extern const SecAsn1Template kSecAsn1OCSPDReplyTemplate[];
extern const SecAsn1Template kSecAsn1OCSPDRepliesTemplate[];

#ifdef  __cplusplus
}
#endif

#endif	/* _OCSP_TEMPLATES_H_ */
