/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

#include <x509.h>
#include <Policy.h>

void upcase(char *s) {
	unsigned int i; 

	for (i = 0; i < strlen(s); i++) 
		s[i] = toupper(s[i]);
}

int convertTime(const Time &t1, struct tm &t2) {
	unsigned int y, m, d, h, mn, s, a;
	int i, j, b, c, status; 

	if (t1.utcTime.is_present()) {
		if ((status = t1.utcTime.get_value(y, m, d, h, mn, s, i, j)) != 0)
			return status; 
    }
    else if (t1.generalizedTime.is_present()) {
      if ((status = t1.generalizedTime.get_value(y, m, d, h, mn, s, a, b, c)) != 0)
        return status; 
	}
	else
		// There's no there there 
		return POL_NO_TIME_TOULOUSE; 

    t2.tm_year = y - 1900;
    t2.tm_mon = m;
    t2.tm_mday = d; 
    t2.tm_hour = h;
    t2.tm_min = mn;
    t2.tm_sec = s; 

	return 0; 

}

bool Pol_IsSubject(const GeneralName &requestor, const x509_certificate &cert) {
	int i, j, status; 
	x509_Extension *ext; 
	r_buffer_t buff; 
	XsubjectAltName altnames; 

	// If the requestor is the subject DN, return true
	if (cert.tbsCertificate.subject.is_present()) {
		if (requestor == cert.tbsCertificate.subject)
			return true;
		else
			return false; 
	}

	// Otherwise, what about altnames? 
	for (i = 0; i < cert.tbsCertificate.extensions.value.get_child_count(); i++) {
		ext = cert.tbsCertificate.extensions.value[i];
		if (CP_IsSubjAltOid(ext->extnID)){
			if ((status = ext->extnValue.get_value(buff.data, buff.data_len)) != 0)
				return false; 
			if ((status = altnames.read(buff)) != 0)
				return false; 
			for (j = 0; j < altnames.get_child_count(); j++) {
				if (requestor == *altnames[j])
					return true;
			}
		}
	}

	return false; 
}

bool Pol_IsMyRA(const GeneralName &requestor) {
	char ra[STRSIZE], key[STRSIZE];
	int i;
	asn_x500name name; 
	r_buffer_t buff; 
	
	for (i = 1; ; i++) {
		sprintf(key, GEN_RA "%d", i);
		if (IniReadString(GEN_SECTION, key, ra, STRSIZE)) {
			buff.data = (unsigned char *) &ra[0]; 
			buff.data_len = strlen(ra); 
			if (name.set_value_UTF8(buff) != 0)
				return false; 
			if (requestor == name)
				return true; 
		}
		else 
			break; 
	}
	return false; 
}

int Pol_Compare(const CertTemplate &certtemp, const x509_certificate &cert) {
	if (certtemp.version.value.is_present())
		// Need to convert Version to asn_integer?
		if (! (certtemp.version.value == cert.tbsCertificate.version))
			return POL_VERSION_MISMATCH; 
	// No need to check the serial number; it was used in lookup
	if (certtemp.signingAlg.value.is_present())
		if (! (certtemp.signingAlg.value == cert.tbsCertificate.signature))
			return POL_SIGALG_MISMATCH; 
	// No need to check the issuer; it was used in the lookup
	if (certtemp.validity.value.is_present())
		// Need to convert OptionalValidity to Validity?
		if (! (certtemp.validity.value == cert.tbsCertificate.validity))
			return POL_VALIDITY_MISMATCH; 
	if (certtemp.subject.value.is_present())
		if (! (certtemp.subject.value == cert.tbsCertificate.subject))
			return POL_SUBJECT_MISMATCH; 
	if (certtemp.publicKey.value.is_present())
		if (! (certtemp.publicKey.value == cert.tbsCertificate.subjectPublicKeyInfo))
			return POL_PUBKEY_MISMATCH; 
	if (certtemp.issuerUID.value.is_present())
		if (! (certtemp.issuerUID.value == cert.tbsCertificate.issuerUniqueID))
			return POL_ISSUID_MISMATCH; 
	if (certtemp.subjectUID.value.is_present())
		if (! (certtemp.subjectUID.value == cert.tbsCertificate.subjectUniqueID))
			return POL_SUBJUID_MISMATCH; 
	if (certtemp.extensions.value.is_present() && cert.tbsCertificate.extensions.value.is_present)
		if (! (certtemp.extensions.value == cert.tbsCertificate.extensions.value))
			return POL_EXTENSION_MISMATCH; 

	return 0; 
}

int Pol_RevokeFilter(const GeneralName &requestor, const CertTemplate &certtemp, 
					 const ReasonFlags &reason, const Time &revdate) {
	char ee[STRSIZE]; 
	int status; 
	long val; 
//	uint32 state;
//	x509_certificate *cert; 
//	utf8String comment;
//	struct tm issued_time, lastChange_time;

	// If I'm a CA, check that an RA is the requestor
	if (IniAmICA()) {
		if (Pol_IsMyRA(requestor))
			return 0; 
	}
	// If I'm a RA, check whether policy allows EEs to request any revokation,
	// only their own, or none at all
	IniReadString(CP_SECTION, CP_EEREVOKE, ee, STRSIZE, CP_EEREVOKEDEF);
	upcase(ee); 
	if (ee == CP_EEREVOKENONE)
		return POL_NO_EE_REVOKE; 

	// Get the cert based on the issuer name and serial number in the template
	if ((status = certtemp.serialNumber.value.get_value(val)) != 0)
		return status; 
/*	// Uncomment when RICL is available
	if ((status = Jnh_RICLLookup(&(certtemp.issuer.value), val, &cert, 
									state, &comment, issued_time, lastChange_time)) != 0)
		return status;

	// If only accepting self revokes, check if this is one. 
	if (ee == CP_EEREVOKESELF) {
		if (!Pol_IsSubject(requestor, *cert))
			return POL_SELF_REVOKE_ONLY; 
	}

	// Check any other specified fields; they must be identical to the ones in the cert
	if ((status = Pol_Compare(certtemp, *cert)) != 0)
		return status; 
*/
	return 0; 

}

int Pol_RevokeVerify(const GeneralName &requestor, const CertTemplate &certtemp, 
					 const ReasonFlags &reason, const Time &revdate) {
	uint32 status;
	long val; 
//	uint32 state;
//	x509_certificate *cert; 
//	utf8String comment;
//	struct tm issued_time, lastChange_time, t1, t2;


	// Check that I am an RA or a CA 
	if (!IniAmIRA() && !IniAmICA())
		return POL_NOT_RA_CA;

	// Check that the revokation time is before the cert expiration date (inclusive)
	
	if ((status = certtemp.serialNumber.value.get_value(val)) != 0)
		return status; 
/*	// Uncomment when RICL is available
	if ((status = Jnh_RICLLookup(&(certtemp.issuer.value), val, &cert, 
									state, &comment, issued_time, lastChange_time)) != 0)
		return status;
	
	if ((status = convertTime(cert->tbsCertificate.validity.notAfter, t1)) != 0)
		return status; 
	if ((status = convertTime(revdate, t2)) != 0)
		return status; 

	if (difftime(mktime(&t2), mktime(&t1)) >= 0)
		return 0;
	else
		return POL_LATE_REVTIME; 

*/
	return 0;
}

