/***********************************************************
* $Id: PKCS11Certificate.java 91 2007-08-16 15:39:21Z wolfgang.glas $
*
* PKCS11 provider of the OpenSC project http://www.opensc-project.org
*
* Copyright (C) 2002-2006 ev-i Informationstechnologie GmbH
*
* Created: Jul 18, 2006
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
***********************************************************/
package org.opensc.pkcs11.wrap;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.security.auth.x500.X500Principal;
/**
* This class manages X509 certificates stored on the card.
*
* @author wglas
*/
public class PKCS11Certificate extends PKCS11Object
{
public static final int CKC_X_509 = 0x00000000;
public static final int CKC_X_509_ATTR_CERT = 0x00000001;
public static final int CKC_VENDOR_DEFINED = 0x80000000;
private X500Principal subject;
private X500Principal issuer;
private BigInteger serial;
/**
* @param session The session to which we are associated.
* @param handle The object handle as returned by PKCS11Object.enumRawObjects().
* @throws PKCS11Exception Upon errors when retrieving the information for
* this certificate from the token.
*/
protected PKCS11Certificate(PKCS11Session session, long handle)
throws PKCS11Exception
{
super(session, handle);
byte[] raw_subject = getRawAttribute(PKCS11Attribute.CKA_SUBJECT);
this.subject = new X500Principal(raw_subject);
byte[] raw_issuer = getRawAttribute(PKCS11Attribute.CKA_ISSUER);
this.issuer = new X500Principal(raw_issuer);
byte[] raw_serial = getRawAttribute(PKCS11Attribute.CKA_SERIAL_NUMBER);
this.serial = new BigInteger(raw_serial);
}
/**
* Fetches all certificates stored in the specified slot.
*
* @param session The session of which to find the certificates.
* @return The list of all certificates found in this slot.
* @throws PKCS11Exception Upon errors from the underlying PKCS11 module.
*/
public static List<PKCS11Certificate> getCertificates(PKCS11Session session) throws PKCS11Exception
{
long[] handles = enumRawObjects(session,PKCS11Object.CKO_CERTIFICATE);
List<PKCS11Certificate> ret = new ArrayList<PKCS11Certificate>(handles.length);
for (int i = 0; i < handles.length; i++)
{
ret.add(new PKCS11Certificate(session,handles[i]));
}
return ret;
}
/**
* Store a signed certificate to the token and return a reference to the newly created token
* object.
*
* Currently, the only supported certificate type is X.509.
*
* @param session The session in which to create the new certificate.
* @param cert The certificate to be stored. Currently the certificate must
* be an extension of {@link X509Certificate}.
* @param label An optional label for the certificate object on the token.
* @param trusted The PKCS#11 trusted flag of the certificate.
* @return A reference to the newly created certificate object on the token.
* @throws PKCS11Exception Upon errors from the underlying PKCS11 module.
* @throws CertificateEncodingException If the certificae could not be serialized
* or the certificate in not an X.509 certificate.
*/
public static PKCS11Certificate storeCertificate(PKCS11Session session, Certificate cert,
String label, boolean trusted) throws PKCS11Exception, CertificateEncodingException
{
if (!(cert instanceof X509Certificate))
throw new CertificateEncodingException("Only X.509 certificates are supported.");
X509Certificate x509 = (X509Certificate)cert;
try
{
int nAttrs = 7;
if (label != null) ++nAttrs;
PKCS11Attribute[] attrs = new PKCS11Attribute[nAttrs];
attrs[0] = new PKCS11Attribute(PKCS11Attribute.CKA_CLASS,CKO_CERTIFICATE);
attrs[1] = new PKCS11Attribute(PKCS11Attribute.CKA_CERTIFICATE_TYPE,CKC_X_509);
attrs[2] = new PKCS11Attribute(PKCS11Attribute.CKA_SUBJECT,
x509.getSubjectX500Principal().getEncoded());
attrs[3] = new PKCS11Attribute(PKCS11Attribute.CKA_ISSUER,
x509.getIssuerX500Principal().getEncoded());
attrs[4] = new PKCS11Attribute(PKCS11Attribute.CKA_SERIAL_NUMBER,
x509.getSerialNumber().toByteArray());
attrs[5] = new PKCS11Attribute(PKCS11Attribute.CKA_VALUE,cert.getEncoded());
attrs[6] = new PKCS11Attribute(PKCS11Attribute.CKA_TRUSTED,trusted);
if (label != null)
attrs[7] = new PKCS11Attribute(PKCS11Attribute.CKA_LABEL,label.getBytes("UTF-8"));
return new PKCS11Certificate(session,PKCS11Object.createObject(session, attrs));
} catch (UnsupportedEncodingException e)
{
throw new CertificateEncodingException("Unexpected error during utf-8 encoding",e);
}
}
/**
* @return The decoded X509 certificate of this entry.
* @throws CertificateException Upon errors when decoding the
* raw ASN1 encoded certificate from the token.
*/
public Certificate getCertificate() throws PKCS11Exception, CertificateException
{
byte[] asn1_certificate = getRawAttribute(PKCS11Attribute.CKA_VALUE);
CertificateFactory factory =
CertificateFactory.getInstance("X.509");
ByteArrayInputStream is = new ByteArrayInputStream(asn1_certificate);
return factory.generateCertificate(is);
}
/**
* @return Returns the issuer, which is the value of the CKA_ISSUER attribute.
*/
public X500Principal getIssuer()
{
return this.issuer;
}
/**
* @return Returns the serial, which is the value of the CKA_SERIAL_NUMBER attribute.
*/
public BigInteger getSerial()
{
return this.serial;
}
/**
* @return Returns the subject, which is the value of the CKA_SUBJECT attribute.
*/
public X500Principal getSubject()
{
return this.subject;
}
}