Pegasus Enhancement Proposal (PEP)

PEP #: 74

Title: SSLContext and Certificate verification interface enhancement

Version: 1.0

Created: 28 May 2003

Authors: Nag Boranna

Status: Accepted

Version History:

Version Date Author Change Description
1.0 28 May 2003  Nag Boranna Initial Submission
1.1 30 June 2003  Nag Boranna Updated Status
       

 


Abstract: Enhance SSLContext to accept certificate and key in two separate files instead of one. Enhance the SSL certificate verification callback interface to provide more information about the certificate to client applications and allow them to set the error code.


Definition of the Problem

SSLContext

SSLContext currently take trust store path and certificate file path as parameters in its private constructor. Trust store contains the trusted certificates from other systems and the certificate file contains the server certificate as well as its private key. The certificate in this file is expected to be exported on to the clients and the key is private to the server. Having both in the same file makes it hard to protect the private key while allowing the certificate to be read and exported to other systems.

SSL Certificate verification callback

Pegasus supports a callback function to be passed by the client applications to verify the default certificate verification results from the SSL library (e.g., openSSL library). Certain information from the certificate is extracted and passed to the callback function. The client applications (in their callback function) can verify the default verification result and accept or reject the certificate. Current implementation does not support the callback function to override the result on failed default verification, it does not provide information such as certificate serial number, version number and validity dates.

Proposed Solution

SSLContext enhancement

Modify the private constructor of SSLContext to take certificate file path and key file path as two separate parameters. To maintain backward compatibility, both certificate and key are read from the certificate file path when the key file path is empty (String::EMPTY). If the key file path is empty and the key is not present in the certificate file path, will result in an exception and the cimserver will not start. The new SSLContext private constructor will be as shown below.

    SSLContext(
        const String& trustPath,                       // trust store file path
        const String& certPath,                        // file path containing the server certificate 
        const String& keyPath,                         // file path containing the server's private key
        SSLCertificateVerifyFunction* verifyCert,      // certificate verification callback function
        const String& randomFile);                     // file path containing the random number seed 

Create a new config property "sslKeyFilePath" in addition to "sslCertificateFilePath". This new property (sslKeyFilePath) can be used to specify the key file path, the earlier property (sslCertificateFilePath) can be used to specify the certificate file. Modify the CIMServer class get the certificate and key file paths from these config properties and pass them to the SSLContext constructor.

SSL Certificate verification callback enhancement

Enhance SSLCertificateInfo class to define error codes, include new methods to set the error code by the applications and to get the error string, version, serial number, not before and not after dates. With this enhancement, applications can override the result of failed default verification by setting the appropriate error code. The new SSLCertificateInfo class will be as shown below.

	/** This class provides the interface that a client gets as argument
		to certificate verification call back function.
	*/
	class PEGASUS_COMMON_LINKAGE SSLCertificateInfo
	{
	public:
		//
		// Text marked in Red is the new code that is added.
		//

		//
		// Certificate validation result/error codes.
		//
		static const int    V_OK;
		static const int    V_ERR_UNABLE_TO_GET_ISSUER_CERT;
		static const int    V_ERR_UNABLE_TO_GET_CRL;
		static const int    V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
		static const int    V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
		static const int    V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
		static const int    V_ERR_CERT_SIGNATURE_FAILURE;
		static const int    V_ERR_CRL_SIGNATURE_FAILURE;
		static const int    V_ERR_CERT_NOT_YET_VALID;
		static const int    V_ERR_CERT_HAS_EXPIRED;
		static const int    V_ERR_CRL_NOT_YET_VALID;
		static const int    V_ERR_CRL_HAS_EXPIRED;
		static const int    V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
		static const int    V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
		static const int    V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
		static const int    V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
		static const int    V_ERR_OUT_OF_MEM;
		static const int    V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
		static const int    V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
		static const int    V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
		static const int    V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
		static const int    V_ERR_CERT_CHAIN_TOO_LONG;
		static const int    V_ERR_CERT_REVOKED;
		static const int    V_ERR_INVALID_CA;
		static const int    V_ERR_PATH_LENGTH_EXCEEDED;
		static const int    V_ERR_INVALID_PURPOSE;
		static const int    V_ERR_CERT_UNTRUSTED;
		static const int    V_ERR_CERT_REJECTED;
		static const int    V_ERR_SUBJECT_ISSUER_MISMATCH;
		static const int    V_ERR_AKID_SKID_MISMATCH;
		static const int    V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
		static const int    V_ERR_KEYUSAGE_NO_CERTSIGN;
		static const int    V_ERR_APPLICATION_VERIFICATION;


		/** Constructor for a SSLCertificateInfo object.
		Note: Do not use this constructor, instead use the private constructor.
		The constructor is not for client applications use, it is intended to be
		used only by the CIMServer.
		@param subjectName subject name of the certificate.
		@param issuerName  issuer name of the certificate.
		@param errorDepth  depth of the certificate chain.
		@param errorCode   error code from the default verification of the
		certificate by the Open SSL library.
		@param respCode   result code from the default verification of the
		certificate by the Open SSL library.
		*/
		SSLCertificateInfo(
			const String subjectName,
			const String issuerName,
			const int errorDepth,
			const int errorCode,
			const int respCode);

		/** Copy constructor for a SSLCertificateInfo object.
		@param certificateInfo SSLCertificateInfo object to copy
		*/
		SSLCertificateInfo(const SSLCertificateInfo& certificateInfo);

		~SSLCertificateInfo();

		/** Gets the subject name of the certificate
		@return a string containing the subject name.
		*/
		String getSubjectName() const;

		/** Gets the issuer name of the certificate
		@return a string containing the issuer name.
		*/
		String getIssuerName() const;

		/** Gets the depth of the certificate chain
		@return an int containing the depth of the certificate chain
		*/
		int getErrorDepth() const;

		/** Gets the preverify error code
		@return an int containing the preverification error code
		*/
		int getErrorCode() const;
	  
		/** Sets the error code
		@param errorCode error code to be set
		*/
		void setErrorCode(const int errorCode);

		/** Gets the preverify error string
		@return a string containing the preverification error string
		*/
		String getErrorString() const;

		/** Gets the notAfter date from the validity period of
		the certificate.
		@return a string containing the notAfter date.
		*/
		String getNotAfter() const;

		/** Gets the notBefore date from the validity period of
		the certificate.
		@return a string containing the notBefore date.
		*/
		String getNotBefore() const;

		/** Gets the serialNumber value from the certificate.
		@return a long integer containing the issuer name.
		*/
		long getSerialNumber() const;

		/** Gets the version (version number) value from the certificate.
		@return a int containing the version.
		*/
		Uint32 getVersion() const;

		/** Gets the preverify response code
		@return an int containing the preverify response code
		*/
		int getResponseCode() const;

		/** Sets the response code
		Note: Do not use this function, the value set using this function
		is ignored.
		@param respCode response code to be set.
		*/
		void setResponseCode(const int respCode);

	private:

		/** Constructor for a SSLCertificateInfo object.
		@param subjectName subject name of the certificate.
		@param issuerName  issuer name of the certificate.
		@param version version number value from the certificate.
		@param serailNumber serial number value from the certificate.
		@param notAfter notAfter date from the validity period of the certificate.
		@param notBefore notBefore date from the validity period of the certificate.
		@param depth  depth of the certificate chain.
		@param errorCode   error code from the default verification of the
		certificate by the Open SSL library.
		@param errorString error message from the default verification of the
		certificate by the Open SSL library.
		@param respCode   result code from the default verification of the
		certificate by the Open SSL library.
		*/
		SSLCertificateInfo(
			const String subjectName,
			const String issuerName,
			const Uint32 versionNumber,
			const long   serialNumber,
			const CIMDateTime notBefore,
			const CIMDateTime notAfter,
			const Uint32 depth,
			const Uint32 errorCode,
			const String errorString,
			const Uint32 respCode);

		SSLCertificateInfo();
		
		SSLCertificateInfoRep* _rep;

		friend int prepareForCallback(int preverifyOk, X509_STORE_CTX *ctx);

	};

Rationale

Having the server certificate and private key in one file makes it hard for the administrators to protect the private key while exposing the public certificate to be read and exported on to other client systems. Keeping them in two separate files will solve this problem.

Not allowing applications to override the certificate verification result beats the purpose of having the callback function. Modifying the interface to allow for applications to set the error code will help applications to override the result on a failed default verification. Providing more information about the certificate being verified will be useful for client applications to make the decision of accepting or rejecting the certificate.

Schedule

ActionPlannedActualComment
PEP Submitted05/30/0305/28/03
PEP Reviewed06/06/03 06/10/03
PEP Approved06/13/03 06/13/03
Code Committed06/20/0306/26/03


Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; IBM Corp.; The Open Group

Permission is hereby granted, free of charge, to any person obtaining a copy  of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED  "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.