/* * CertID.java * PROJECT: JDigiDoc * DESCRIPTION: Digi Doc functions for creating * and reading signed documents. * AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia *================================================== * Copyright (C) AS Sertifitseerimiskeskus * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * GNU Lesser General Public Licence is available at * http://www.gnu.org/copyleft/lesser.html *================================================== */ package es.uji.security.crypto.openxades.digidoc; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; import java.math.BigInteger; import java.security.cert.X509Certificate; import java.util.ArrayList; import es.uji.security.crypto.openxades.digidoc.utils.ConvertUtils; import es.uji.security.util.Base64; /** * Models the ETSI <Cert> element Holds info about a certificate but not the certificate itself. * Such elements will be serialized under the <CompleteCertificateRefs> element * * @author Veiko Sinivee * @version 1.0 */ public class CertID implements Serializable { /** certs digest algorithm */ private String m_digestAlgorithm; /** elements id atribute if present */ private String m_id; /** certs digest data */ private byte[] m_digestValue; /** certs issuer DN */ private String m_issuer; /** certs issuer serial number */ private BigInteger m_serial; /** parent object - Signature ref */ private Signature m_signature; /** CertID type - signer, responder, tsa */ private int m_type; /** possible certid type values */ public static final int CERTID_TYPE_UNKNOWN = 0; public static final int CERTID_TYPE_SIGNER = 1; public static final int CERTID_TYPE_RESPONDER = 2; public static final int CERTID_TYPE_TSA = 3; /** * Creates new CertID and initializes everything to null */ public CertID() { m_id = null; m_digestAlgorithm = null; m_digestValue = null; m_serial = null; m_issuer = null; m_signature = null; m_type = CERTID_TYPE_UNKNOWN; } /** * Creates new CertID * * @param certId * OCSP responders cert id (in XML) * @param digAlg * OCSP responders certs digest algorithm id/uri * @param digest * OCSP responders certs digest * @param serial * OCSP responders certs issuers serial number * @param type * CertID type: signer, responder or tsa * @throws DigiDocException * for validation errors */ public CertID(String certId, String digAlg, byte[] digest, BigInteger serial, String issuer, int type) throws DigiDocException { setId(certId); setDigestAlgorithm(digAlg); setDigestValue(digest); setSerial(serial); if (issuer != null) setIssuer(issuer); setType(type); m_signature = null; } /** * Creates new CertID by using default values for id and responders cert * * @param sig * Signature object * @param cert * OCSP certificate for creating this ref data * @param type * CertID type: signer, responder or tsa * @throws DigiDocException * for validation errors */ public CertID(Signature sig, X509Certificate cert, int type) throws DigiDocException { setId(sig.getId() + "-RESPONDER_CERTINFO"); setDigestAlgorithm(SignedDoc.SHA1_DIGEST_ALGORITHM); byte[] digest = null; try { digest = SignedDoc.digest(cert.getEncoded()); } catch (Exception ex) { DigiDocException.handleException(ex, DigiDocException.ERR_CALCULATE_DIGEST); } setDigestValue(digest); setSerial(cert.getSerialNumber()); setIssuer(cert.getIssuerDN().getName()); setType(type); } /** * Accessor for Signature attribute * * @return value of Signature attribute */ public Signature getSignature() { return m_signature; } /** * Mutator for Signature attribute * * @param uprops * value of Signature attribute */ public void setSignature(Signature sig) { m_signature = sig; } /** * Accessor for certId attribute * * @return value of certId attribute */ public String getId() { return m_id; } /** * Mutator for certId attribute * * @param str * new value for certId attribute * @throws DigiDocException * for validation errors */ public void setId(String str) throws DigiDocException { if (m_signature != null && !m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3) && !m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_4)) { DigiDocException ex = validateId(str); if (ex != null) throw ex; } m_id = str; } /** * Helper method to validate an certificate id * * @param str * input data * @return exception or null for ok */ private DigiDocException validateId(String str) { DigiDocException ex = null; if (str == null && !m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3) && !m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_4)) ex = new DigiDocException(DigiDocException.ERR_RESPONDER_CERT_ID, "Cert Id must be in form: <signature-id>-RESPONDER_CERTINFO", null); return ex; } /** * Accessor for digestAlgorithm attribute * * @return value of digestAlgorithm attribute */ public String getDigestAlgorithm() { return m_digestAlgorithm; } /** * Mutator for digestAlgorithm attribute * * @param str * new value for digestAlgorithm attribute * @throws DigiDocException * for validation errors */ public void setDigestAlgorithm(String str) throws DigiDocException { DigiDocException ex = validateDigestAlgorithm(str); if (ex != null) throw ex; m_digestAlgorithm = str; } /** * Helper method to validate a digest algorithm * * @param str * input data * @return exception or null for ok */ private DigiDocException validateDigestAlgorithm(String str) { DigiDocException ex = null; if (str == null || !str.equals(SignedDoc.SHA1_DIGEST_ALGORITHM)) ex = new DigiDocException(DigiDocException.ERR_CERT_DIGEST_ALGORITHM, "Currently supports only SHA1 digest algorithm", null); return ex; } /** * Accessor for digestValue attribute * * @return value of digestValue attribute */ public byte[] getDigestValue() { return m_digestValue; } /** * Mutator for digestValue attribute * * @param data * new value for digestValue attribute * @throws DigiDocException * for validation errors */ public void setDigestValue(byte[] data) throws DigiDocException { DigiDocException ex = validateDigestValue(data); if (ex != null) throw ex; m_digestValue = data; } /** * Helper method to validate a digest value * * @param data * input data * @return exception or null for ok */ private DigiDocException validateDigestValue(byte[] data) { DigiDocException ex = null; if (data == null || data.length != SignedDoc.SHA1_DIGEST_LENGTH) ex = new DigiDocException(DigiDocException.ERR_DIGEST_LENGTH, "SHA1 digest data is allways 20 bytes of length", null); return ex; } /** * Accessor for serial attribute * * @return value of serial attribute */ public BigInteger getSerial() { return m_serial; } /** * Mutator for serial attribute * * @param str * new value for serial attribute * @throws DigiDocException * for validation errors */ public void setSerial(BigInteger i) throws DigiDocException { DigiDocException ex = validateSerial(i); if (ex != null) throw ex; m_serial = i; } /** * Helper method to validate a serial * * @param str * input data * @return exception or null for ok */ private DigiDocException validateSerial(BigInteger i) { DigiDocException ex = null; if (i == null) // check the uri somehow ??? ex = new DigiDocException(DigiDocException.ERR_CERT_SERIAL, "Certificates serial number cannot be empty!", null); return ex; } /** * Accessor for issuer attribute * * @return value of issuer attribute */ public String getIssuer() { return m_issuer; } /** * Mutator for issuer attribute * * @param str * new value for issuer attribute * @throws DigiDocException * for validation errors */ public void setIssuer(String str) throws DigiDocException { DigiDocException ex = validateIssuer(str); if (ex != null) throw ex; m_issuer = str; } /** * Helper method to validate issuer * * @param str * input data * @return exception or null for ok */ private DigiDocException validateIssuer(String str) { DigiDocException ex = null; if (str == null) ex = new DigiDocException(DigiDocException.ERR_CREF_ISSUER, "Issuer name cannot be empty", null); return ex; } /** * Accessor for type attribute * * @return value of type attribute */ public int getType() { return m_type; } /** * Mutator for type attribute * * @param n * new value for issuer attribute * @throws DigiDocException * for validation errors */ public void setType(int n) throws DigiDocException { DigiDocException ex = validateType(n); if (ex != null) throw ex; m_type = n; } /** * Helper method to validate type * * @param n * input data * @return exception or null for ok */ private DigiDocException validateType(int n) { DigiDocException ex = null; if (n < 0 || n > CERTID_TYPE_TSA) ex = new DigiDocException(DigiDocException.ERR_CERTID_TYPE, "Invalid CertID type", null); return ex; } /** * Helper method to validate the whole CertID object * * @return a possibly empty list of DigiDocException objects */ public ArrayList validate() { ArrayList errs = new ArrayList(); DigiDocException ex = validateId(m_id); if (ex != null) errs.add(ex); ex = validateDigestAlgorithm(m_digestAlgorithm); if (ex != null) errs.add(ex); ex = validateDigestValue(m_digestValue); if (ex != null) errs.add(ex); ex = validateSerial(m_serial); if (ex != null) errs.add(ex); ex = validateIssuer(m_issuer); if (ex != null) errs.add(ex); ex = validateType(m_type); if (ex != null) errs.add(ex); return errs; } /** * Converts the CertID to XML form * * @return XML representation of CertID */ public byte[] toXML() throws DigiDocException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { if (m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3) || m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_4)) { bos.write(ConvertUtils.str2data("<Cert>")); } else { bos.write(ConvertUtils.str2data("<Cert Id=\"")); bos.write(ConvertUtils.str2data(m_id)); bos.write(ConvertUtils.str2data("\">")); } bos.write(ConvertUtils.str2data("\n<CertDigest>\n<DigestMethod Algorithm=\"")); bos.write(ConvertUtils.str2data(m_digestAlgorithm)); bos.write(ConvertUtils.str2data("\">\n</DigestMethod>\n<DigestValue>")); bos.write(ConvertUtils.str2data(Base64.encodeBytes(m_digestValue))); bos.write(ConvertUtils.str2data("</DigestValue>\n</CertDigest>\n")); // In version 1.3 we use correct <IssuerSerial> content // e.g. subelements <X509IssuerName> and <X509SerialNumber> if (m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3) || m_signature.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_4)) { bos.write(ConvertUtils.str2data("<IssuerSerial>")); bos.write(ConvertUtils.str2data("\n<X509IssuerName xmlns=\"")); bos.write(ConvertUtils.str2data(SignedDoc.xmlns_xmldsig)); bos.write(ConvertUtils.str2data("\">")); bos.write(ConvertUtils.str2data(m_issuer)); bos.write(ConvertUtils.str2data("</X509IssuerName>")); bos.write(ConvertUtils.str2data("\n<X509SerialNumber xmlns=\"")); bos.write(ConvertUtils.str2data(SignedDoc.xmlns_xmldsig)); bos.write(ConvertUtils.str2data("\">")); bos.write(ConvertUtils.str2data(m_serial.toString())); bos.write(ConvertUtils.str2data("</X509SerialNumber>\n")); bos.write(ConvertUtils.str2data("</IssuerSerial>\n")); } else { // in prior versions we used wrong <IssuerSerial> content bos.write(ConvertUtils.str2data("<IssuerSerial>")); bos.write(ConvertUtils.str2data(m_serial.toString())); bos.write(ConvertUtils.str2data("</IssuerSerial>\n")); } bos.write(ConvertUtils.str2data("</Cert>")); } catch (IOException ex) { DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT); } return bos.toByteArray(); } /** * Returns the stringified form of CompleteCertificateRefs * * @return CompleteCertificateRefs string representation */ public String toString() { String str = null; try { str = new String(toXML()); } catch (Exception ex) { } return str; } }