update to android master on May.30.2016, not tested
parent
395d66ef9e
commit
56dacf31bd
@ -0,0 +1,225 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
|
||||
import org.bouncycastle.asn1.ocsp.ResponseData;
|
||||
import org.bouncycastle.asn1.ocsp.SingleResponse;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.Certificate;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.operator.ContentVerifier;
|
||||
import org.bouncycastle.operator.ContentVerifierProvider;
|
||||
import org.bouncycastle.util.Encodable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* BasicOCSPResponse ::= SEQUENCE {
|
||||
* tbsResponseData ResponseData,
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING,
|
||||
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
|
||||
* </pre>
|
||||
*/
|
||||
public class BasicOCSPResp
|
||||
implements Encodable
|
||||
{
|
||||
private BasicOCSPResponse resp;
|
||||
private ResponseData data;
|
||||
private Extensions extensions;
|
||||
|
||||
public BasicOCSPResp(
|
||||
BasicOCSPResponse resp)
|
||||
{
|
||||
this.resp = resp;
|
||||
this.data = resp.getTbsResponseData();
|
||||
this.extensions = Extensions.getInstance(resp.getTbsResponseData().getResponseExtensions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DER encoding of the tbsResponseData field.
|
||||
* @return DER encoding of tbsResponseData
|
||||
*/
|
||||
public byte[] getTBSResponseData()
|
||||
{
|
||||
try
|
||||
{
|
||||
return resp.getTbsResponseData().getEncoded(ASN1Encoding.DER);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the algorithm identifier describing the signature used in the response.
|
||||
*
|
||||
* @return an AlgorithmIdentifier
|
||||
*/
|
||||
public AlgorithmIdentifier getSignatureAlgorithmID()
|
||||
{
|
||||
return resp.getSignatureAlgorithm();
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return data.getVersion().getValue().intValue() + 1;
|
||||
}
|
||||
|
||||
public RespID getResponderId()
|
||||
{
|
||||
return new RespID(data.getResponderID());
|
||||
}
|
||||
|
||||
public Date getProducedAt()
|
||||
{
|
||||
return OCSPUtils.extractDate(data.getProducedAt());
|
||||
}
|
||||
|
||||
public SingleResp[] getResponses()
|
||||
{
|
||||
ASN1Sequence s = data.getResponses();
|
||||
SingleResp[] rs = new SingleResp[s.size()];
|
||||
|
||||
for (int i = 0; i != rs.length; i++)
|
||||
{
|
||||
rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i)));
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
public boolean hasExtensions()
|
||||
{
|
||||
return extensions != null;
|
||||
}
|
||||
|
||||
public Extension getExtension(ASN1ObjectIdentifier oid)
|
||||
{
|
||||
if (extensions != null)
|
||||
{
|
||||
return extensions.getExtension(oid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List getExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
|
||||
public ASN1ObjectIdentifier getSignatureAlgOID()
|
||||
{
|
||||
return resp.getSignatureAlgorithm().getAlgorithm();
|
||||
}
|
||||
|
||||
public byte[] getSignature()
|
||||
{
|
||||
return resp.getSignature().getOctets();
|
||||
}
|
||||
|
||||
public X509CertificateHolder[] getCerts()
|
||||
{
|
||||
//
|
||||
// load the certificates if we have any
|
||||
//
|
||||
if (resp.getCerts() != null)
|
||||
{
|
||||
ASN1Sequence s = resp.getCerts();
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
X509CertificateHolder[] certs = new X509CertificateHolder[s.size()];
|
||||
|
||||
for (int i = 0; i != certs.length; i++)
|
||||
{
|
||||
certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i)));
|
||||
}
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
return OCSPUtils.EMPTY_CERTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OCSPUtils.EMPTY_CERTS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* verify the signature against the tbsResponseData object we contain.
|
||||
*/
|
||||
public boolean isSignatureValid(
|
||||
ContentVerifierProvider verifierProvider)
|
||||
throws OCSPException
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentVerifier verifier = verifierProvider.get(resp.getSignatureAlgorithm());
|
||||
OutputStream vOut = verifier.getOutputStream();
|
||||
|
||||
vOut.write(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER));
|
||||
vOut.close();
|
||||
|
||||
return verifier.verify(this.getSignature());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception processing sig: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the ASN.1 encoded representation of this object.
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
throws IOException
|
||||
{
|
||||
return resp.getEncoded();
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof BasicOCSPResp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BasicOCSPResp r = (BasicOCSPResp)o;
|
||||
|
||||
return resp.equals(r.resp);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return resp.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1GeneralizedTime;
|
||||
import org.bouncycastle.asn1.DERBitString;
|
||||
import org.bouncycastle.asn1.DERGeneralizedTime;
|
||||
import org.bouncycastle.asn1.DERNull;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
|
||||
import org.bouncycastle.asn1.ocsp.CertStatus;
|
||||
import org.bouncycastle.asn1.ocsp.ResponseData;
|
||||
import org.bouncycastle.asn1.ocsp.RevokedInfo;
|
||||
import org.bouncycastle.asn1.ocsp.SingleResponse;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.CRLReason;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
|
||||
/**
|
||||
* Generator for basic OCSP response objects.
|
||||
*/
|
||||
public class BasicOCSPRespBuilder
|
||||
{
|
||||
private List list = new ArrayList();
|
||||
private Extensions responseExtensions = null;
|
||||
private RespID responderID;
|
||||
|
||||
private class ResponseObject
|
||||
{
|
||||
CertificateID certId;
|
||||
CertStatus certStatus;
|
||||
ASN1GeneralizedTime thisUpdate;
|
||||
ASN1GeneralizedTime nextUpdate;
|
||||
Extensions extensions;
|
||||
|
||||
public ResponseObject(
|
||||
CertificateID certId,
|
||||
CertificateStatus certStatus,
|
||||
Date thisUpdate,
|
||||
Date nextUpdate,
|
||||
Extensions extensions)
|
||||
{
|
||||
this.certId = certId;
|
||||
|
||||
if (certStatus == null)
|
||||
{
|
||||
this.certStatus = new CertStatus();
|
||||
}
|
||||
else if (certStatus instanceof UnknownStatus)
|
||||
{
|
||||
this.certStatus = new CertStatus(2, DERNull.INSTANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
RevokedStatus rs = (RevokedStatus)certStatus;
|
||||
|
||||
if (rs.hasRevocationReason())
|
||||
{
|
||||
this.certStatus = new CertStatus(
|
||||
new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), CRLReason.lookup(rs.getRevocationReason())));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.certStatus = new CertStatus(
|
||||
new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), null));
|
||||
}
|
||||
}
|
||||
|
||||
this.thisUpdate = new DERGeneralizedTime(thisUpdate);
|
||||
|
||||
if (nextUpdate != null)
|
||||
{
|
||||
this.nextUpdate = new DERGeneralizedTime(nextUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nextUpdate = null;
|
||||
}
|
||||
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
public SingleResponse toResponse()
|
||||
throws Exception
|
||||
{
|
||||
return new SingleResponse(certId.toASN1Primitive(), certStatus, thisUpdate, nextUpdate, extensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* basic constructor
|
||||
*/
|
||||
public BasicOCSPRespBuilder(
|
||||
RespID responderID)
|
||||
{
|
||||
this.responderID = responderID;
|
||||
}
|
||||
|
||||
/**
|
||||
* construct with the responderID to be the SHA-1 keyHash of the passed in public key.
|
||||
*
|
||||
* @param key the key info of the responder public key.
|
||||
* @param digCalc a SHA-1 digest calculator
|
||||
*/
|
||||
public BasicOCSPRespBuilder(
|
||||
SubjectPublicKeyInfo key,
|
||||
DigestCalculator digCalc)
|
||||
throws OCSPException
|
||||
{
|
||||
this.responderID = new RespID(key, digCalc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a response for a particular Certificate ID.
|
||||
*
|
||||
* @param certID certificate ID details
|
||||
* @param certStatus status of the certificate - null if okay
|
||||
*/
|
||||
public BasicOCSPRespBuilder addResponse(
|
||||
CertificateID certID,
|
||||
CertificateStatus certStatus)
|
||||
{
|
||||
this.addResponse(certID, certStatus, new Date(), null, null);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a response for a particular Certificate ID.
|
||||
*
|
||||
* @param certID certificate ID details
|
||||
* @param certStatus status of the certificate - null if okay
|
||||
* @param singleExtensions optional extensions
|
||||
*/
|
||||
public BasicOCSPRespBuilder addResponse(
|
||||
CertificateID certID,
|
||||
CertificateStatus certStatus,
|
||||
Extensions singleExtensions)
|
||||
{
|
||||
this.addResponse(certID, certStatus, new Date(), null, singleExtensions);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a response for a particular Certificate ID.
|
||||
*
|
||||
* @param certID certificate ID details
|
||||
* @param nextUpdate date when next update should be requested
|
||||
* @param certStatus status of the certificate - null if okay
|
||||
* @param singleExtensions optional extensions
|
||||
*/
|
||||
public BasicOCSPRespBuilder addResponse(
|
||||
CertificateID certID,
|
||||
CertificateStatus certStatus,
|
||||
Date nextUpdate,
|
||||
Extensions singleExtensions)
|
||||
{
|
||||
this.addResponse(certID, certStatus, new Date(), nextUpdate, singleExtensions);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a response for a particular Certificate ID.
|
||||
*
|
||||
* @param certID certificate ID details
|
||||
* @param thisUpdate date this response was valid on
|
||||
* @param nextUpdate date when next update should be requested
|
||||
* @param certStatus status of the certificate - null if okay
|
||||
*/
|
||||
public BasicOCSPRespBuilder addResponse(
|
||||
CertificateID certID,
|
||||
CertificateStatus certStatus,
|
||||
Date thisUpdate,
|
||||
Date nextUpdate)
|
||||
{
|
||||
this.addResponse(certID, certStatus, thisUpdate, nextUpdate, null);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a response for a particular Certificate ID.
|
||||
*
|
||||
* @param certID certificate ID details
|
||||
* @param thisUpdate date this response was valid on
|
||||
* @param nextUpdate date when next update should be requested
|
||||
* @param certStatus status of the certificate - null if okay
|
||||
* @param singleExtensions optional extensions
|
||||
*/
|
||||
public BasicOCSPRespBuilder addResponse(
|
||||
CertificateID certID,
|
||||
CertificateStatus certStatus,
|
||||
Date thisUpdate,
|
||||
Date nextUpdate,
|
||||
Extensions singleExtensions)
|
||||
{
|
||||
list.add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extensions for the response.
|
||||
*
|
||||
* @param responseExtensions the extension object to carry.
|
||||
*/
|
||||
public BasicOCSPRespBuilder setResponseExtensions(
|
||||
Extensions responseExtensions)
|
||||
{
|
||||
this.responseExtensions = responseExtensions;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public BasicOCSPResp build(
|
||||
ContentSigner signer,
|
||||
X509CertificateHolder[] chain,
|
||||
Date producedAt)
|
||||
throws OCSPException
|
||||
{
|
||||
Iterator it = list.iterator();
|
||||
|
||||
ASN1EncodableVector responses = new ASN1EncodableVector();
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
responses.add(((ResponseObject)it.next()).toResponse());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception creating Request", e);
|
||||
}
|
||||
}
|
||||
|
||||
ResponseData tbsResp = new ResponseData(responderID.toASN1Primitive(), new ASN1GeneralizedTime(producedAt), new DERSequence(responses), responseExtensions);
|
||||
DERBitString bitSig;
|
||||
|
||||
try
|
||||
{
|
||||
OutputStream sigOut = signer.getOutputStream();
|
||||
|
||||
sigOut.write(tbsResp.getEncoded(ASN1Encoding.DER));
|
||||
sigOut.close();
|
||||
|
||||
bitSig = new DERBitString(signer.getSignature());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception processing TBSRequest: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
AlgorithmIdentifier sigAlgId = signer.getAlgorithmIdentifier();
|
||||
|
||||
DERSequence chainSeq = null;
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
for (int i = 0; i != chain.length; i++)
|
||||
{
|
||||
v.add(chain[i].toASN1Structure());
|
||||
}
|
||||
|
||||
chainSeq = new DERSequence(v);
|
||||
}
|
||||
|
||||
return new BasicOCSPResp(new BasicOCSPResponse(tbsResp, sigAlgId, bitSig, chainSeq));
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1OctetString;
|
||||
import org.bouncycastle.asn1.DERNull;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.ocsp.CertID;
|
||||
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
import org.bouncycastle.operator.DigestCalculatorProvider;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
|
||||
public class CertificateID
|
||||
{
|
||||
public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
|
||||
|
||||
private final CertID id;
|
||||
|
||||
public CertificateID(
|
||||
CertID id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
throw new IllegalArgumentException("'id' cannot be null");
|
||||
}
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* create from an issuer certificate and the serial number of the
|
||||
* certificate it signed.
|
||||
*
|
||||
* @param issuerCert issuing certificate
|
||||
* @param number serial number
|
||||
*
|
||||
* @exception OCSPException if any problems occur creating the id fields.
|
||||
*/
|
||||
public CertificateID(
|
||||
DigestCalculator digestCalculator, X509CertificateHolder issuerCert,
|
||||
BigInteger number)
|
||||
throws OCSPException
|
||||
{
|
||||
this.id = createCertID(digestCalculator, issuerCert, new ASN1Integer(number));
|
||||
}
|
||||
|
||||
public ASN1ObjectIdentifier getHashAlgOID()
|
||||
{
|
||||
return id.getHashAlgorithm().getAlgorithm();
|
||||
}
|
||||
|
||||
public byte[] getIssuerNameHash()
|
||||
{
|
||||
return id.getIssuerNameHash().getOctets();
|
||||
}
|
||||
|
||||
public byte[] getIssuerKeyHash()
|
||||
{
|
||||
return id.getIssuerKeyHash().getOctets();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the serial number for the certificate associated
|
||||
* with this request.
|
||||
*/
|
||||
public BigInteger getSerialNumber()
|
||||
{
|
||||
return id.getSerialNumber().getValue();
|
||||
}
|
||||
|
||||
public boolean matchesIssuer(X509CertificateHolder issuerCert, DigestCalculatorProvider digCalcProvider)
|
||||
throws OCSPException
|
||||
{
|
||||
try
|
||||
{
|
||||
return createCertID(digCalcProvider.get(id.getHashAlgorithm()), issuerCert, id.getSerialNumber()).equals(id);
|
||||
}
|
||||
catch (OperatorCreationException e)
|
||||
{
|
||||
throw new OCSPException("unable to create digest calculator: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public CertID toASN1Primitive()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object o)
|
||||
{
|
||||
if (!(o instanceof CertificateID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CertificateID obj = (CertificateID)o;
|
||||
|
||||
return id.toASN1Primitive().equals(obj.id.toASN1Primitive());
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return id.toASN1Primitive().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CertificateID for a new serial number derived from a previous one
|
||||
* calculated for the same CA certificate.
|
||||
*
|
||||
* @param original the previously calculated CertificateID for the CA.
|
||||
* @param newSerialNumber the serial number for the new certificate of interest.
|
||||
*
|
||||
* @return a new CertificateID for newSerialNumber
|
||||
*/
|
||||
public static CertificateID deriveCertificateID(CertificateID original, BigInteger newSerialNumber)
|
||||
{
|
||||
return new CertificateID(new CertID(original.id.getHashAlgorithm(), original.id.getIssuerNameHash(), original.id.getIssuerKeyHash(), new ASN1Integer(newSerialNumber)));
|
||||
}
|
||||
|
||||
private static CertID createCertID(DigestCalculator digCalc, X509CertificateHolder issuerCert, ASN1Integer serialNumber)
|
||||
throws OCSPException
|
||||
{
|
||||
try
|
||||
{
|
||||
OutputStream dgOut = digCalc.getOutputStream();
|
||||
|
||||
dgOut.write(issuerCert.toASN1Structure().getSubject().getEncoded(ASN1Encoding.DER));
|
||||
dgOut.close();
|
||||
|
||||
ASN1OctetString issuerNameHash = new DEROctetString(digCalc.getDigest());
|
||||
|
||||
SubjectPublicKeyInfo info = issuerCert.getSubjectPublicKeyInfo();
|
||||
|
||||
dgOut = digCalc.getOutputStream();
|
||||
|
||||
dgOut.write(info.getPublicKeyData().getBytes());
|
||||
dgOut.close();
|
||||
|
||||
ASN1OctetString issuerKeyHash = new DEROctetString(digCalc.getDigest());
|
||||
|
||||
return new CertID(digCalc.getAlgorithmIdentifier(), issuerNameHash, issuerKeyHash, serialNumber);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("problem creating ID: " + e, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
public interface CertificateStatus
|
||||
{
|
||||
public static final CertificateStatus GOOD = null;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
public class OCSPException
|
||||
extends Exception
|
||||
{
|
||||
private Throwable cause;
|
||||
|
||||
public OCSPException(
|
||||
String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public OCSPException(
|
||||
String name,
|
||||
Throwable cause)
|
||||
{
|
||||
super(name);
|
||||
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public Throwable getCause()
|
||||
{
|
||||
return cause;
|
||||
}
|
||||
}
|
@ -0,0 +1,259 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1Exception;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1OutputStream;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPRequest;
|
||||
import org.bouncycastle.asn1.ocsp.Request;
|
||||
import org.bouncycastle.asn1.x509.Certificate;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.cert.CertIOException;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.operator.ContentVerifier;
|
||||
import org.bouncycastle.operator.ContentVerifierProvider;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* OCSPRequest ::= SEQUENCE {
|
||||
* tbsRequest TBSRequest,
|
||||
* optionalSignature [0] EXPLICIT Signature OPTIONAL }
|
||||
*
|
||||
* TBSRequest ::= SEQUENCE {
|
||||
* version [0] EXPLICIT Version DEFAULT v1,
|
||||
* requestorName [1] EXPLICIT GeneralName OPTIONAL,
|
||||
* requestList SEQUENCE OF Request,
|
||||
* requestExtensions [2] EXPLICIT Extensions OPTIONAL }
|
||||
*
|
||||
* Signature ::= SEQUENCE {
|
||||
* signatureAlgorithm AlgorithmIdentifier,
|
||||
* signature BIT STRING,
|
||||
* certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
|
||||
*
|
||||
* Version ::= INTEGER { v1(0) }
|
||||
*
|
||||
* Request ::= SEQUENCE {
|
||||
* reqCert CertID,
|
||||
* singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
|
||||
*
|
||||
* CertID ::= SEQUENCE {
|
||||
* hashAlgorithm AlgorithmIdentifier,
|
||||
* issuerNameHash OCTET STRING, -- Hash of Issuer's DN
|
||||
* issuerKeyHash OCTET STRING, -- Hash of Issuers public key
|
||||
* serialNumber CertificateSerialNumber }
|
||||
* </pre>
|
||||
*/
|
||||
public class OCSPReq
|
||||
{
|
||||
private static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0];
|
||||
|
||||
private OCSPRequest req;
|
||||
private Extensions extensions;
|
||||
|
||||
public OCSPReq(
|
||||
OCSPRequest req)
|
||||
{
|
||||
this.req = req;
|
||||
this.extensions = req.getTbsRequest().getRequestExtensions();
|
||||
}
|
||||
|
||||
public OCSPReq(
|
||||
byte[] req)
|
||||
throws IOException
|
||||
{
|
||||
this(new ASN1InputStream(req));
|
||||
}
|
||||
|
||||
private OCSPReq(
|
||||
ASN1InputStream aIn)
|
||||
throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
this.req = OCSPRequest.getInstance(aIn.readObject());
|
||||
if (req == null)
|
||||
{
|
||||
throw new CertIOException("malformed request: no request data found");
|
||||
}
|
||||
this.extensions = req.getTbsRequest().getRequestExtensions();
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new CertIOException("malformed request: " + e.getMessage(), e);
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
throw new CertIOException("malformed request: " + e.getMessage(), e);
|
||||
}
|
||||
catch (ASN1Exception e)
|
||||
{
|
||||
throw new CertIOException("malformed request: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getVersionNumber()
|
||||
{
|
||||
return req.getTbsRequest().getVersion().getValue().intValue() + 1;
|
||||
}
|
||||
|
||||
public GeneralName getRequestorName()
|
||||
{
|
||||
return GeneralName.getInstance(req.getTbsRequest().getRequestorName());
|
||||
}
|
||||
|
||||
public Req[] getRequestList()
|
||||
{
|
||||
ASN1Sequence seq = req.getTbsRequest().getRequestList();
|
||||
Req[] requests = new Req[seq.size()];
|
||||
|
||||
for (int i = 0; i != requests.length; i++)
|
||||
{
|
||||
requests[i] = new Req(Request.getInstance(seq.getObjectAt(i)));
|
||||
}
|
||||
|
||||
return requests;
|
||||
}
|
||||
|
||||
public boolean hasExtensions()
|
||||
{
|
||||
return extensions != null;
|
||||
}
|
||||
|
||||
public Extension getExtension(ASN1ObjectIdentifier oid)
|
||||
{
|
||||
if (extensions != null)
|
||||
{
|
||||
return extensions.getExtension(oid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List getExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the object identifier representing the signature algorithm
|
||||
*/
|
||||
public ASN1ObjectIdentifier getSignatureAlgOID()
|
||||
{
|
||||
if (!this.isSigned())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return req.getOptionalSignature().getSignatureAlgorithm().getAlgorithm();
|
||||
}
|
||||
|
||||
public byte[] getSignature()
|
||||
{
|
||||
if (!this.isSigned())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return req.getOptionalSignature().getSignature().getOctets();
|
||||
}
|
||||
|
||||
public X509CertificateHolder[] getCerts()
|
||||
{
|
||||
//
|
||||
// load the certificates if we have any
|
||||
//
|
||||
if (req.getOptionalSignature() != null)
|
||||
{
|
||||
ASN1Sequence s = req.getOptionalSignature().getCerts();
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
X509CertificateHolder[] certs = new X509CertificateHolder[s.size()];
|
||||
|
||||
for (int i = 0; i != certs.length; i++)
|
||||
{
|
||||
certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i)));
|
||||
}
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
return EMPTY_CERTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EMPTY_CERTS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this request is signed.
|
||||
*
|
||||
* @return true if signed false otherwise.
|
||||
*/
|
||||
public boolean isSigned()
|
||||
{
|
||||
return req.getOptionalSignature() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify the signature against the TBSRequest object we contain.
|
||||
*/
|
||||
public boolean isSignatureValid(
|
||||
ContentVerifierProvider verifierProvider)
|
||||
throws OCSPException
|
||||
{
|
||||
if (!this.isSigned())
|
||||
{
|
||||
throw new OCSPException("attempt to verify signature on unsigned object");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ContentVerifier verifier = verifierProvider.get(req.getOptionalSignature().getSignatureAlgorithm());
|
||||
OutputStream sOut = verifier.getOutputStream();
|
||||
|
||||
sOut.write(req.getTbsRequest().getEncoded(ASN1Encoding.DER));
|
||||
|
||||
return verifier.verify(this.getSignature());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception processing signature: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the ASN.1 encoded representation of this object.
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
||||
|
||||
aOut.writeObject(req);
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.DERBitString;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPRequest;
|
||||
import org.bouncycastle.asn1.ocsp.Request;
|
||||
import org.bouncycastle.asn1.ocsp.Signature;
|
||||
import org.bouncycastle.asn1.ocsp.TBSRequest;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
|
||||
public class OCSPReqBuilder
|
||||
{
|
||||
private List list = new ArrayList();
|
||||
private GeneralName requestorName = null;
|
||||
private Extensions requestExtensions = null;
|
||||
|
||||
private class RequestObject
|
||||
{
|
||||
CertificateID certId;
|
||||
Extensions extensions;
|
||||
|
||||
public RequestObject(
|
||||
CertificateID certId,
|
||||
Extensions extensions)
|
||||
{
|
||||
this.certId = certId;
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
public Request toRequest()
|
||||
throws Exception
|
||||
{
|
||||
return new Request(certId.toASN1Primitive(), extensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a request for the given CertificateID.
|
||||
*
|
||||
* @param certId certificate ID of interest
|
||||
*/
|
||||
public OCSPReqBuilder addRequest(
|
||||
CertificateID certId)
|
||||
{
|
||||
list.add(new RequestObject(certId, null));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a request with extensions
|
||||
*
|
||||
* @param certId certificate ID of interest
|
||||
* @param singleRequestExtensions the extensions to attach to the request
|
||||
*/
|
||||
public OCSPReqBuilder addRequest(
|
||||
CertificateID certId,
|
||||
Extensions singleRequestExtensions)
|
||||
{
|
||||
list.add(new RequestObject(certId, singleRequestExtensions));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the requestor name to the passed in X500Principal
|
||||
*
|
||||
* @param requestorName a X500Principal representing the requestor name.
|
||||
*/
|
||||
public OCSPReqBuilder setRequestorName(
|
||||
X500Name requestorName)
|
||||
{
|
||||
this.requestorName = new GeneralName(GeneralName.directoryName, requestorName);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OCSPReqBuilder setRequestorName(
|
||||
GeneralName requestorName)
|
||||
{
|
||||
this.requestorName = requestorName;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OCSPReqBuilder setRequestExtensions(
|
||||
Extensions requestExtensions)
|
||||
{
|
||||
this.requestExtensions = requestExtensions;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private OCSPReq generateRequest(
|
||||
ContentSigner contentSigner,
|
||||
X509CertificateHolder[] chain)
|
||||
throws OCSPException
|
||||
{
|
||||
Iterator it = list.iterator();
|
||||
|
||||
ASN1EncodableVector requests = new ASN1EncodableVector();
|
||||
|
||||
while (it.hasNext())
|
||||
{
|
||||
try
|
||||
{
|
||||
requests.add(((RequestObject)it.next()).toRequest());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception creating Request", e);
|
||||
}
|
||||
}
|
||||
|
||||
TBSRequest tbsReq = new TBSRequest(requestorName, new DERSequence(requests), requestExtensions);
|
||||
|
||||
Signature signature = null;
|
||||
|
||||
if (contentSigner != null)
|
||||
{
|
||||
if (requestorName == null)
|
||||
{
|
||||
throw new OCSPException("requestorName must be specified if request is signed.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
OutputStream sOut = contentSigner.getOutputStream();
|
||||
|
||||
sOut.write(tbsReq.getEncoded(ASN1Encoding.DER));
|
||||
|
||||
sOut.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("exception processing TBSRequest: " + e, e);
|
||||
}
|
||||
|
||||
DERBitString bitSig = new DERBitString(contentSigner.getSignature());
|
||||
|
||||
AlgorithmIdentifier sigAlgId = contentSigner.getAlgorithmIdentifier();
|
||||
|
||||
if (chain != null && chain.length > 0)
|
||||
{
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
for (int i = 0; i != chain.length; i++)
|
||||
{
|
||||
v.add(chain[i].toASN1Structure());
|
||||
}
|
||||
|
||||
signature = new Signature(sigAlgId, bitSig, new DERSequence(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
signature = new Signature(sigAlgId, bitSig);
|
||||
}
|
||||
}
|
||||
|
||||
return new OCSPReq(new OCSPRequest(tbsReq, signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an unsigned request
|
||||
*
|
||||
* @return the OCSPReq
|
||||
* @throws org.bouncycastle.ocsp.OCSPException
|
||||
*/
|
||||
public OCSPReq build()
|
||||
throws OCSPException
|
||||
{
|
||||
return generateRequest(null, null);
|
||||
}
|
||||
|
||||
public OCSPReq build(
|
||||
ContentSigner signer,
|
||||
X509CertificateHolder[] chain)
|
||||
throws OCSPException, IllegalArgumentException
|
||||
{
|
||||
if (signer == null)
|
||||
{
|
||||
throw new IllegalArgumentException("no signer specified");
|
||||
}
|
||||
|
||||
return generateRequest(signer, chain);
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Exception;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1Primitive;
|
||||
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPResponse;
|
||||
import org.bouncycastle.asn1.ocsp.ResponseBytes;
|
||||
import org.bouncycastle.cert.CertIOException;
|
||||
|
||||
public class OCSPResp
|
||||
{
|
||||
public static final int SUCCESSFUL = 0; // Response has valid confirmations
|
||||
public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request
|
||||
public static final int INTERNAL_ERROR = 2; // Internal error in issuer
|
||||
public static final int TRY_LATER = 3; // Try again later
|
||||
// (4) is not used
|
||||
public static final int SIG_REQUIRED = 5; // Must sign the request
|
||||
public static final int UNAUTHORIZED = 6; // Request unauthorized
|
||||
|
||||
private OCSPResponse resp;
|
||||
|
||||
public OCSPResp(
|
||||
OCSPResponse resp)
|
||||
{
|
||||
this.resp = resp;
|
||||
}
|
||||
|
||||
public OCSPResp(
|
||||
byte[] resp)
|
||||
throws IOException
|
||||
{
|
||||
this(new ByteArrayInputStream(resp));
|
||||
}
|
||||
|
||||
public OCSPResp(
|
||||
InputStream resp)
|
||||
throws IOException
|
||||
{
|
||||
this(new ASN1InputStream(resp));
|
||||
}
|
||||
|
||||
private OCSPResp(
|
||||
ASN1InputStream aIn)
|
||||
throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
this.resp = OCSPResponse.getInstance(aIn.readObject());
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new CertIOException("malformed response: " + e.getMessage(), e);
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
throw new CertIOException("malformed response: " + e.getMessage(), e);
|
||||
}
|
||||
catch (ASN1Exception e)
|
||||
{
|
||||
throw new CertIOException("malformed response: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (resp == null)
|
||||
{
|
||||
throw new CertIOException("malformed response: no response data found");
|
||||
}
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
{
|
||||
return this.resp.getResponseStatus().getValue().intValue();
|
||||
}
|
||||
|
||||
public Object getResponseObject()
|
||||
throws OCSPException
|
||||
{
|
||||
ResponseBytes rb = this.resp.getResponseBytes();
|
||||
|
||||
if (rb == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (rb.getResponseType().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic))
|
||||
{
|
||||
try
|
||||
{
|
||||
ASN1Primitive obj = ASN1Primitive.fromByteArray(rb.getResponse().getOctets());
|
||||
return new BasicOCSPResp(BasicOCSPResponse.getInstance(obj));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("problem decoding object: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
return rb.getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the ASN.1 encoded representation of this object.
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
throws IOException
|
||||
{
|
||||
return resp.getEncoded();
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof OCSPResp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OCSPResp r = (OCSPResp)o;
|
||||
|
||||
return resp.equals(r.resp);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return resp.hashCode();
|
||||
}
|
||||
|
||||
public OCSPResponse toASN1Structure()
|
||||
{
|
||||
return resp;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1OctetString;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPResponse;
|
||||
import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
|
||||
import org.bouncycastle.asn1.ocsp.ResponseBytes;
|
||||
|
||||
/**
|
||||
* base generator for an OCSP response - at the moment this only supports the
|
||||
* generation of responses containing BasicOCSP responses.
|
||||
*/
|
||||
public class OCSPRespBuilder
|
||||
{
|
||||
public static final int SUCCESSFUL = 0; // Response has valid confirmations
|
||||
public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request
|
||||
public static final int INTERNAL_ERROR = 2; // Internal error in issuer
|
||||
public static final int TRY_LATER = 3; // Try again later
|
||||
// (4) is not used
|
||||
public static final int SIG_REQUIRED = 5; // Must sign the request
|
||||
public static final int UNAUTHORIZED = 6; // Request unauthorized
|
||||
|
||||
public OCSPResp build(
|
||||
int status,
|
||||
Object response)
|
||||
throws OCSPException
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status), null));
|
||||
}
|
||||
|
||||
if (response instanceof BasicOCSPResp)
|
||||
{
|
||||
BasicOCSPResp r = (BasicOCSPResp)response;
|
||||
ASN1OctetString octs;
|
||||
|
||||
try
|
||||
{
|
||||
octs = new DEROctetString(r.getEncoded());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new OCSPException("can't encode object.", e);
|
||||
}
|
||||
|
||||
ResponseBytes rb = new ResponseBytes(
|
||||
OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs);
|
||||
|
||||
return new OCSPResp(new OCSPResponse(
|
||||
new OCSPResponseStatus(status), rb));
|
||||
}
|
||||
|
||||
throw new OCSPException("unknown response object");
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1GeneralizedTime;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
|
||||
class OCSPUtils
|
||||
{
|
||||
static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0];
|
||||
|
||||
static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());
|
||||
static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
|
||||
|
||||
static Date extractDate(ASN1GeneralizedTime time)
|
||||
{
|
||||
try
|
||||
{
|
||||
return time.getDate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException("exception processing GeneralizedTime: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static Set getCriticalExtensionOIDs(Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EMPTY_SET;
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));
|
||||
}
|
||||
|
||||
static Set getNonCriticalExtensionOIDs(Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EMPTY_SET;
|
||||
}
|
||||
|
||||
// TODO: should probably produce a set that imposes correct ordering
|
||||
return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));
|
||||
}
|
||||
|
||||
static List getExtensionOIDs(Extensions extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import org.bouncycastle.asn1.ocsp.Request;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
|
||||
public class Req
|
||||
{
|
||||
private Request req;
|
||||
|
||||
public Req(
|
||||
Request req)
|
||||
{
|
||||
this.req = req;
|
||||
}
|
||||
|
||||
public CertificateID getCertID()
|
||||
{
|
||||
return new CertificateID(req.getReqCert());
|
||||
}
|
||||
|
||||
public Extensions getSingleRequestExtensions()
|
||||
{
|
||||
return req.getSingleRequestExtensions();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ocsp.ResponseData;
|
||||
import org.bouncycastle.asn1.ocsp.SingleResponse;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
|
||||
public class RespData
|
||||
{
|
||||
private ResponseData data;
|
||||
|
||||
public RespData(
|
||||
ResponseData data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return data.getVersion().getValue().intValue() + 1;
|
||||
}
|
||||
|
||||
public RespID getResponderId()
|
||||
{
|
||||
return new RespID(data.getResponderID());
|
||||
}
|
||||
|
||||
public Date getProducedAt()
|
||||
{
|
||||
return OCSPUtils.extractDate(data.getProducedAt());
|
||||
}
|
||||
|
||||
public SingleResp[] getResponses()
|
||||
{
|
||||
ASN1Sequence s = data.getResponses();
|
||||
SingleResp[] rs = new SingleResp[s.size()];
|
||||
|
||||
for (int i = 0; i != rs.length; i++)
|
||||
{
|
||||
rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i)));
|
||||
}
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
public Extensions getResponseExtensions()
|
||||
{
|
||||
return data.getResponseExtensions();
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bouncycastle.asn1.DERNull;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.ocsp.ResponderID;
|
||||
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
|
||||
/**
|
||||
* Carrier for a ResponderID.
|
||||
*/
|
||||
public class RespID
|
||||
{
|
||||
public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
|
||||
|
||||
ResponderID id;
|
||||
|
||||
public RespID(
|
||||
ResponderID id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public RespID(
|
||||
X500Name name)
|
||||
{
|
||||
this.id = new ResponderID(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a RespID based on the public key of the responder.
|
||||
*
|
||||
* @param subjectPublicKeyInfo the info structure for the responder public key.
|
||||
* @param digCalc a SHA-1 digest calculator.
|
||||
* @throws OCSPException on exception creating ID.
|
||||
*/
|
||||
public RespID(
|
||||
SubjectPublicKeyInfo subjectPublicKeyInfo,
|
||||
DigestCalculator digCalc)
|
||||
throws OCSPException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!digCalc.getAlgorithmIdentifier().equals(HASH_SHA1))
|
||||
{
|
||||
throw new IllegalArgumentException("only SHA-1 can be used with RespID");
|
||||
}
|
||||
|
||||
OutputStream digOut = digCalc.getOutputStream();
|
||||
|
||||
digOut.write(subjectPublicKeyInfo.getPublicKeyData().getBytes());
|
||||
digOut.close();
|
||||
|
||||
this.id = new ResponderID(new DEROctetString(digCalc.getDigest()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new OCSPException("problem creating ID: " + e, e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResponderID toASN1Primitive()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object o)
|
||||
{
|
||||
if (!(o instanceof RespID))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RespID obj = (RespID)o;
|
||||
|
||||
return id.equals(obj.id);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1GeneralizedTime;
|
||||
import org.bouncycastle.asn1.ocsp.RevokedInfo;
|
||||
import org.bouncycastle.asn1.x509.CRLReason;
|
||||
|
||||
/**
|
||||
* wrapper for the RevokedInfo object
|
||||
*/
|
||||
public class RevokedStatus
|
||||
implements CertificateStatus
|
||||
{
|
||||
RevokedInfo info;
|
||||
|
||||
public RevokedStatus(
|
||||
RevokedInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public RevokedStatus(
|
||||
Date revocationDate,
|
||||
int reason)
|
||||
{
|
||||
this.info = new RevokedInfo(new ASN1GeneralizedTime(revocationDate), CRLReason.lookup(reason));
|
||||
}
|
||||
|
||||
public Date getRevocationTime()
|
||||
{
|
||||
return OCSPUtils.extractDate(info.getRevocationTime());
|
||||
}
|
||||
|
||||
public boolean hasRevocationReason()
|
||||
{
|
||||
return (info.getRevocationReason() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the revocation reason. Note: this field is optional, test for it
|
||||
* with hasRevocationReason() first.
|
||||
* @return the revocation reason value.
|
||||
* @exception IllegalStateException if a reason is asked for and none is avaliable
|
||||
*/
|
||||
public int getRevocationReason()
|
||||
{
|
||||
if (info.getRevocationReason() == null)
|
||||
{
|
||||
throw new IllegalStateException("attempt to get a reason where none is available");
|
||||
}
|
||||
|
||||
return info.getRevocationReason().getValue().intValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ocsp.CertStatus;
|
||||
import org.bouncycastle.asn1.ocsp.RevokedInfo;
|
||||
import org.bouncycastle.asn1.ocsp.SingleResponse;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.Extensions;
|
||||
|
||||
public class SingleResp
|
||||
{
|
||||
private SingleResponse resp;
|
||||
private Extensions extensions;
|
||||
|
||||
public SingleResp(
|
||||
SingleResponse resp)
|
||||
{
|
||||
this.resp = resp;
|
||||
this.extensions = resp.getSingleExtensions();
|
||||
}
|
||||
|
||||
public CertificateID getCertID()
|
||||
{
|
||||
return new CertificateID(resp.getCertID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status object for the response - null indicates good.
|
||||
*
|
||||
* @return the status object for the response, null if it is good.
|
||||
*/
|
||||
public CertificateStatus getCertStatus()
|
||||
{
|
||||
CertStatus s = resp.getCertStatus();
|
||||
|
||||
if (s.getTagNo() == 0)
|
||||
{
|
||||
return null; // good
|
||||
}
|
||||
else if (s.getTagNo() == 1)
|
||||
{
|
||||
return new RevokedStatus(RevokedInfo.getInstance(s.getStatus()));
|
||||
}
|
||||
|
||||
return new UnknownStatus();
|
||||
}
|
||||
|
||||
public Date getThisUpdate()
|
||||
{
|
||||
return OCSPUtils.extractDate(resp.getThisUpdate());
|
||||
}
|
||||
|
||||
/**
|
||||
* return the NextUpdate value - note: this is an optional field so may
|
||||
* be returned as null.
|
||||
*
|
||||
* @return nextUpdate, or null if not present.
|
||||
*/
|
||||
public Date getNextUpdate()
|
||||
{
|
||||
if (resp.getNextUpdate() == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return OCSPUtils.extractDate(resp.getNextUpdate());
|
||||
}
|
||||
|
||||
public boolean hasExtensions()
|
||||
{
|
||||
return extensions != null;
|
||||
}
|
||||
|
||||
public Extension getExtension(ASN1ObjectIdentifier oid)
|
||||
{
|
||||
if (extensions != null)
|
||||
{
|
||||
return extensions.getExtension(oid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List getExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
|
||||
public Set getNonCriticalExtensionOIDs()
|
||||
{
|
||||
return OCSPUtils.getNonCriticalExtensionOIDs(extensions);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.bouncycastle.cert.ocsp;
|
||||
|
||||
/**
|
||||
* wrapper for the UnknownInfo object
|
||||
*/
|
||||
public class UnknownStatus
|
||||
implements CertificateStatus
|
||||
{
|
||||
public UnknownStatus()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.bouncycastle.cert.ocsp.jcajce;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
|
||||
import org.bouncycastle.cert.ocsp.OCSPException;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
|
||||
public class JcaBasicOCSPRespBuilder
|
||||
extends BasicOCSPRespBuilder
|
||||
{
|
||||
public JcaBasicOCSPRespBuilder(PublicKey key, DigestCalculator digCalc)
|
||||
throws OCSPException
|
||||
{
|
||||
super(SubjectPublicKeyInfo.getInstance(key.getEncoded()), digCalc);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.bouncycastle.cert.ocsp.jcajce;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
|
||||
import org.bouncycastle.cert.ocsp.CertificateID;
|
||||
import org.bouncycastle.cert.ocsp.OCSPException;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
|
||||
public class JcaCertificateID
|
||||
extends CertificateID
|
||||
{
|
||||
public JcaCertificateID(DigestCalculator digestCalculator, X509Certificate issuerCert, BigInteger number)
|
||||
throws OCSPException, CertificateEncodingException
|
||||
{
|
||||
super(digestCalculator, new JcaX509CertificateHolder(issuerCert), number);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.bouncycastle.cert.ocsp.jcajce;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.cert.ocsp.OCSPException;
|
||||
import org.bouncycastle.cert.ocsp.RespID;
|
||||
import org.bouncycastle.operator.DigestCalculator;
|
||||
|
||||
public class JcaRespID
|
||||
extends RespID
|
||||
{
|
||||
public JcaRespID(X500Principal name)
|
||||
{
|
||||
super(X500Name.getInstance(name.getEncoded()));
|
||||
}
|
||||
|
||||
public JcaRespID(PublicKey pubKey, DigestCalculator digCalc)
|
||||
throws OCSPException
|
||||
{
|
||||
super(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), digCalc);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<body bgcolor="#ffffff">
|
||||
JCA extensions to the OCSP online certificate status package.
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,65 @@
|
||||
package org.bouncycastle.cms;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1Encoding;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
|
||||
public class PKCS7ProcessableObject
|
||||
implements CMSTypedData
|
||||
{
|
||||
private final ASN1ObjectIdentifier type;
|
||||
private final ASN1Encodable structure;
|
||||
|
||||
public PKCS7ProcessableObject(
|
||||
ASN1ObjectIdentifier type,
|
||||
ASN1Encodable structure)
|
||||
{
|
||||
this.type = type;
|
||||
this.structure = structure;
|
||||
}
|
||||
|
||||
public ASN1ObjectIdentifier getContentType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void write(OutputStream cOut)
|
||||
throws IOException, CMSException
|
||||
{
|
||||
if (structure instanceof ASN1Sequence)
|
||||
{
|
||||
ASN1Sequence s = ASN1Sequence.getInstance(structure);
|
||||
|
||||
for (Iterator it = s.iterator(); it.hasNext();)
|
||||
{
|
||||
ASN1Encodable enc = (ASN1Encodable)it.next();
|
||||
|
||||
cOut.write(enc.toASN1Primitive().getEncoded(ASN1Encoding.DER));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] encoded = structure.toASN1Primitive().getEncoded(ASN1Encoding.DER);
|
||||
int index = 1;
|
||||
|
||||
while ((encoded[index] & 0xff) > 127)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
cOut.write(encoded, index, encoded.length - index);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getContent()
|
||||
{
|
||||
return structure;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.bouncycastle.cms;
|
||||
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
|
||||
public interface PasswordRecipient
|
||||
extends Recipient
|
||||
{
|
||||
public static final int PKCS5_SCHEME2 = 0;
|
||||
public static final int PKCS5_SCHEME2_UTF8 = 1;
|
||||
|
||||
byte[] calculateDerivedKey(int schemeID, AlgorithmIdentifier derivationAlgorithm, int keySize)
|
||||
throws CMSException;
|
||||
|
||||
RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedEncryptedContentKey)
|
||||
throws CMSException;
|
||||
|
||||
int getPasswordConversionScheme();
|
||||
|
||||
char[] getPassword();
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.bouncycastle.cms;
|
||||
|
||||
public interface Recipient
|
||||
{
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package org.bouncycastle.cms;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.operator.InputDecryptor;
|
||||
import org.bouncycastle.operator.MacCalculator;
|
||||
import org.bouncycastle.util.io.TeeInputStream;
|
||||
|
||||
public class RecipientOperator
|
||||
{
|
||||
private final AlgorithmIdentifier algorithmIdentifier;
|
||||
private final Object operator;
|
||||
|
||||
public RecipientOperator(InputDecryptor decryptor)
|
||||
{
|
||||
this.algorithmIdentifier = decryptor.getAlgorithmIdentifier();
|
||||
this.operator = decryptor;
|
||||
}
|
||||
|
||||
public RecipientOperator(MacCalculator macCalculator)
|
||||
{
|
||||
this.algorithmIdentifier = macCalculator.getAlgorithmIdentifier();
|
||||
this.operator = macCalculator;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(InputStream dataIn)
|
||||
{
|
||||
if (operator instanceof InputDecryptor)
|
||||
{
|
||||
return ((InputDecryptor)operator).getInputStream(dataIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TeeInputStream(dataIn, ((MacCalculator)operator).getOutputStream());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMacBased()
|
||||
{
|
||||
return operator instanceof MacCalculator;
|
||||
}
|
||||
|
||||
public byte[] getMac()
|
||||
{
|
||||
return ((MacCalculator)operator).getMac();
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
package org.bouncycastle.openssl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ASN1TaggedObject;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.DERTaggedObject;
|
||||
import org.bouncycastle.asn1.DERUTF8String;
|
||||
|
||||
public class CertificateTrustBlock
|
||||
{
|
||||
private ASN1Sequence uses;
|
||||
private ASN1Sequence prohibitions;
|
||||
private String alias;
|
||||
|
||||
public CertificateTrustBlock(Set<ASN1ObjectIdentifier> uses)
|
||||
{
|
||||
this(null, uses, null);
|
||||
}
|
||||
|
||||
public CertificateTrustBlock(String alias, Set<ASN1ObjectIdentifier> uses)
|
||||
{
|
||||
this(alias, uses, null);
|
||||
}
|
||||
|
||||
public CertificateTrustBlock(String alias, Set<ASN1ObjectIdentifier> uses, Set<ASN1ObjectIdentifier> prohibitions)
|
||||
{
|
||||
this.alias = alias;
|
||||
this.uses = toSequence(uses);
|
||||
this.prohibitions = toSequence(prohibitions);
|
||||
}
|
||||
|
||||
CertificateTrustBlock(byte[] encoded)
|
||||
{
|
||||
ASN1Sequence seq = ASN1Sequence.getInstance(encoded);
|
||||
|
||||
for (Enumeration en = seq.getObjects(); en.hasMoreElements();)
|
||||
{
|
||||
ASN1Encodable obj = (ASN1Encodable)en.nextElement();
|
||||
|
||||
if (obj instanceof ASN1Sequence)
|
||||
{
|
||||
this.uses = ASN1Sequence.getInstance(obj);
|
||||
}
|
||||
else if (obj instanceof ASN1TaggedObject)
|
||||
{
|
||||
this.prohibitions = ASN1Sequence.getInstance((ASN1TaggedObject)obj, false);
|
||||
}
|
||||
else if (obj instanceof DERUTF8String)
|
||||
{
|
||||
this.alias = DERUTF8String.getInstance(obj).getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getAlias()
|
||||
{
|
||||
return alias;
|
||||
}
|
||||
|
||||
public Set<ASN1ObjectIdentifier> getUses()
|
||||
{
|
||||
return toSet(uses);
|
||||
}
|
||||
|
||||
public Set<ASN1ObjectIdentifier> getProhibitions()
|
||||
{
|
||||
return toSet(prohibitions);
|
||||
}
|
||||
|
||||
private Set<ASN1ObjectIdentifier> toSet(ASN1Sequence seq)
|
||||
{
|
||||
if (seq != null)
|
||||
{
|
||||
Set<ASN1ObjectIdentifier> oids = new HashSet<ASN1ObjectIdentifier>(seq.size());
|
||||
|
||||
for (Enumeration en = seq.getObjects(); en.hasMoreElements(); )
|
||||
{
|
||||
oids.add(ASN1ObjectIdentifier.getInstance(en.nextElement()));
|
||||
}
|
||||
|
||||
return oids;
|
||||
}
|
||||
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
private ASN1Sequence toSequence(Set<ASN1ObjectIdentifier> oids)
|
||||
{
|
||||
if (oids == null || oids.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
for (Iterator it = oids.iterator(); it.hasNext();)
|
||||
{
|
||||
v.add((ASN1Encodable)it.next());
|
||||
}
|
||||
|
||||
return new DERSequence(v);
|
||||
}
|
||||
|
||||
ASN1Sequence toASN1Sequence()
|
||||
{
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
if (uses != null)
|
||||
{
|
||||
v.add(uses);
|
||||
}
|
||||
if (prohibitions != null)
|
||||
{
|
||||
v.add(new DERTaggedObject(false, 0, prohibitions));
|
||||
}
|
||||
if (alias != null)
|
||||
{
|
||||
v.add(new DERUTF8String(alias));
|
||||
}
|
||||
|
||||
return new DERSequence(v);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package org.bouncycastle.operator;
|
||||
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
|
||||
public class GenericKey
|
||||
{
|
||||
private AlgorithmIdentifier algorithmIdentifier;
|
||||
private Object representation;
|
||||
|
||||
/**
|
||||
* @deprecated provide an AlgorithmIdentifier.
|
||||
* @param representation key data
|
||||
*/
|
||||
public GenericKey(Object representation)
|
||||
{
|
||||
this.algorithmIdentifier = null;
|
||||
this.representation = representation;
|
||||
}
|
||||
|
||||
public GenericKey(AlgorithmIdentifier algorithmIdentifier, byte[] representation)
|
||||
{
|
||||
this.algorithmIdentifier = algorithmIdentifier;
|
||||
this.representation = representation;
|
||||
}
|
||||
|
||||
protected GenericKey(AlgorithmIdentifier algorithmIdentifier, Object representation)
|
||||
{
|
||||
this.algorithmIdentifier = algorithmIdentifier;
|
||||
this.representation = representation;
|
||||
}
|
||||
|
||||
public AlgorithmIdentifier getAlgorithmIdentifier()
|
||||
{
|
||||
return algorithmIdentifier;
|
||||
}
|
||||
|
||||
public Object getRepresentation()
|
||||
{
|
||||
return representation;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.bouncycastle.operator;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
|
||||
/**
|
||||
* General interface for an operator that is able to produce
|
||||
* an InputStream that will decrypt a stream of encrypted data.
|
||||
*/
|
||||
public interface InputDecryptor
|
||||
{
|
||||
/**
|
||||
* Return the algorithm identifier describing the encryption
|
||||
* algorithm and parameters this decryptor can process.
|
||||
*
|
||||
* @return algorithm oid and parameters.
|
||||
*/
|
||||
AlgorithmIdentifier getAlgorithmIdentifier();
|
||||
|
||||
/**
|
||||
* Wrap the passed in input stream encIn, returning an input stream
|
||||
* that decrypts what it reads from encIn before returning it.
|
||||
*
|
||||
* @param encIn InputStream containing encrypted input.
|
||||
* @return an decrypting InputStream
|
||||
*/
|
||||
InputStream getInputStream(InputStream encIn);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.bouncycastle.operator;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
|
||||
public interface MacCalculator
|
||||
{
|
||||
AlgorithmIdentifier getAlgorithmIdentifier();
|
||||
|
||||
/**
|
||||
* Returns a stream that will accept data for the purpose of calculating
|
||||
* the MAC for later verification. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate
|
||||
* the data on the fly as well.
|
||||
*
|
||||
* @return an OutputStream
|
||||
*/
|
||||
OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Return the calculated MAC based on what has been written to the stream.
|
||||
*
|
||||
* @return calculated MAC.
|
||||
*/
|
||||
byte[] getMac();
|
||||
|
||||
|
||||
/**
|
||||
* Return the key used for calculating the MAC.
|
||||
*
|
||||
* @return the MAC key.
|
||||
*/
|
||||
GenericKey getKey();
|
||||
}
|
@ -0,0 +1,226 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Base class for an application specific object
|
||||
*/
|
||||
public abstract class ASN1ApplicationSpecific
|
||||
extends ASN1Primitive
|
||||
{
|
||||
protected final boolean isConstructed;
|
||||
protected final int tag;
|
||||
protected final byte[] octets;
|
||||
|
||||
ASN1ApplicationSpecific(
|
||||
boolean isConstructed,
|
||||
int tag,
|
||||
byte[] octets)
|
||||
{
|
||||
this.isConstructed = isConstructed;
|
||||
this.tag = tag;
|
||||
this.octets = octets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ASN1ApplicationSpecific from the passed in object, which may be a byte array, or null.
|
||||
*
|
||||
* @param obj the object to be converted.
|
||||
* @return obj's representation as an ASN1ApplicationSpecific object.
|
||||
*/
|
||||
public static ASN1ApplicationSpecific getInstance(Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1ApplicationSpecific)
|
||||
{
|
||||
return (ASN1ApplicationSpecific)obj;
|
||||
}
|
||||
else if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return ASN1ApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("Failed to construct object from byte[]: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
protected static int getLengthOfHeader(byte[] data)
|
||||
{
|
||||
int length = data[1] & 0xff; // TODO: assumes 1 byte tag
|
||||
|
||||
if (length == 0x80)
|
||||
{
|
||||
return 2; // indefinite-length encoding
|
||||
}
|
||||
|
||||
if (length > 127)
|
||||
{
|
||||
int size = length & 0x7f;
|
||||
|
||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
||||
if (size > 4)
|
||||
{
|
||||
throw new IllegalStateException("DER length more than 4 bytes: " + size);
|
||||
}
|
||||
|
||||
return size + 2;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the object is marked as constructed, false otherwise.
|
||||
*
|
||||
* @return true if constructed, otherwise false.
|
||||
*/
|
||||
public boolean isConstructed()
|
||||
{
|
||||
return isConstructed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of this object as a byte[]
|
||||
*
|
||||
* @return the encoded contents of the object.
|
||||
*/
|
||||
public byte[] getContents()
|
||||
{
|
||||
return octets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tag number associated with this object,
|
||||
*
|
||||
* @return the application tag number.
|
||||
*/
|
||||
public int getApplicationTag()
|
||||
{
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enclosed object assuming explicit tagging.
|
||||
*
|
||||
* @return the resulting object
|
||||
* @throws IOException if reconstruction fails.
|
||||
*/
|
||||
public ASN1Primitive getObject()
|
||||
throws IOException
|
||||
{
|
||||
return new ASN1InputStream(getContents()).readObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enclosed object assuming implicit tagging.
|
||||
*
|
||||
* @param derTagNo the type tag that should be applied to the object's contents.
|
||||
* @return the resulting object
|
||||
* @throws IOException if reconstruction fails.
|
||||
*/
|
||||
public ASN1Primitive getObject(int derTagNo)
|
||||
throws IOException
|
||||
{
|
||||
if (derTagNo >= 0x1f)
|
||||
{
|
||||
throw new IOException("unsupported tag number");
|
||||
}
|
||||
|
||||
byte[] orig = this.getEncoded();
|
||||
byte[] tmp = replaceTagNumber(derTagNo, orig);
|
||||
|
||||
if ((orig[0] & BERTags.CONSTRUCTED) != 0)
|
||||
{
|
||||
tmp[0] |= BERTags.CONSTRUCTED;
|
||||
}
|
||||
|
||||
return new ASN1InputStream(tmp).readObject();
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
throws IOException
|
||||
{
|
||||
return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
|
||||
*/
|
||||
void encode(ASN1OutputStream out) throws IOException
|
||||
{
|
||||
int classBits = BERTags.APPLICATION;
|
||||
if (isConstructed)
|
||||
{
|
||||
classBits |= BERTags.CONSTRUCTED;
|
||||
}
|
||||
|
||||
out.writeEncoded(classBits, tag, octets);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1ApplicationSpecific))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1ApplicationSpecific other = (ASN1ApplicationSpecific)o;
|
||||
|
||||
return isConstructed == other.isConstructed
|
||||
&& tag == other.tag
|
||||
&& Arrays.areEqual(octets, other.octets);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);
|
||||
}
|
||||
|
||||
private byte[] replaceTagNumber(int newTag, byte[] input)
|
||||
throws IOException
|
||||
{
|
||||
int tagNo = input[0] & 0x1f;
|
||||
int index = 1;
|
||||
//
|
||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
||||
//
|
||||
if (tagNo == 0x1f)
|
||||
{
|
||||
tagNo = 0;
|
||||
|
||||
int b = input[index++] & 0xff;
|
||||
|
||||
// X.690-0207 8.1.2.4.2
|
||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
||||
{
|
||||
throw new ASN1ParsingException("corrupted stream - invalid high tag number found");
|
||||
}
|
||||
|
||||
while ((b >= 0) && ((b & 0x80) != 0))
|
||||
{
|
||||
tagNo |= (b & 0x7f);
|
||||
tagNo <<= 7;
|
||||
b = input[index++] & 0xff;
|
||||
}
|
||||
|
||||
// tagNo |= (b & 0x7f);
|
||||
}
|
||||
|
||||
byte[] tmp = new byte[input.length - index + 1];
|
||||
|
||||
System.arraycopy(input, index, tmp, 1, tmp.length - 1);
|
||||
|
||||
tmp[0] = (byte)newTag;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
|
||||
/**
|
||||
* Base class for BIT STRING objects
|
||||
*/
|
||||
public abstract class ASN1BitString
|
||||
extends ASN1Primitive
|
||||
implements ASN1String
|
||||
{
|
||||
private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
protected final byte[] data;
|
||||
protected final int padBits;
|
||||
|
||||
/**
|
||||
* @param bitString an int containing the BIT STRING
|
||||
* @return the correct number of pad bits for a bit string defined in
|
||||
* a 32 bit constant
|
||||
*/
|
||||
static protected int getPadBits(
|
||||
int bitString)
|
||||
{
|
||||
int val = 0;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
//
|
||||
// this may look a little odd, but if it isn't done like this pre jdk1.2
|
||||
// JVM's break!
|
||||
//
|
||||
if (i != 0)
|
||||
{
|
||||
if ((bitString >> (i * 8)) != 0)
|
||||
{
|
||||
val = (bitString >> (i * 8)) & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bitString != 0)
|
||||
{
|
||||
val = bitString & 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bits = 1;
|
||||
|
||||
while (((val <<= 1) & 0xFF) != 0)
|
||||
{
|
||||
bits++;
|
||||
}
|
||||
|
||||
return 8 - bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bitString an int containing the BIT STRING
|
||||
* @return the correct number of bytes for a bit string defined in
|
||||
* a 32 bit constant
|
||||
*/
|
||||
static protected byte[] getBytes(int bitString)
|
||||
{
|
||||
if (bitString == 0)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
int bytes = 4;
|
||||
for (int i = 3; i >= 1; i--)
|
||||
{
|
||||
if ((bitString & (0xFF << (i * 8))) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
bytes--;
|
||||
}
|
||||
|
||||
byte[] result = new byte[bytes];
|
||||
for (int i = 0; i < bytes; i++)
|
||||
{
|
||||
result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param data the octets making up the bit string.
|
||||
* @param padBits the number of extra bits at the end of the string.
|
||||
*/
|
||||
public ASN1BitString(
|
||||
byte[] data,
|
||||
int padBits)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new NullPointerException("data cannot be null");
|
||||
}
|
||||
if (data.length == 0 && padBits != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("zero length data with non-zero pad bits");
|
||||
}
|
||||
if (padBits > 7 || padBits < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("pad bits cannot be greater than 7 or less than 0");
|
||||
}
|
||||
|
||||
this.data = Arrays.clone(data);
|
||||
this.padBits = padBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of this BIT STRING
|
||||
*
|
||||
* @return a String representation.
|
||||
*/
|
||||
public String getString()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer("#");
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
||||
|
||||
try
|
||||
{
|
||||
aOut.writeObject(this);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
byte[] string = bOut.toByteArray();
|
||||
|
||||
for (int i = 0; i != string.length; i++)
|
||||
{
|
||||
buf.append(table[(string[i] >>> 4) & 0xf]);
|
||||
buf.append(table[string[i] & 0xf]);
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of the bit string as an int (truncating if necessary)
|
||||
*/
|
||||
public int intValue()
|
||||
{
|
||||
int value = 0;
|
||||
byte[] string = data;
|
||||
|
||||
if (padBits > 0 && data.length <= 4)
|
||||
{
|
||||
string = derForm(data, padBits);
|
||||
}
|
||||
|
||||
for (int i = 0; i != string.length && i != 4; i++)
|
||||
{
|
||||
value |= (string[i] & 0xff) << (8 * i);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the octets contained in this BIT STRING, checking that this BIT STRING really
|
||||
* does represent an octet aligned string. Only use this method when the standard you are
|
||||
* following dictates that the BIT STRING will be octet aligned.
|
||||
*
|
||||
* @return a copy of the octet aligned data.
|
||||
*/
|
||||
public byte[] getOctets()
|
||||
{
|
||||
if (padBits != 0)
|
||||
{
|
||||
throw new IllegalStateException("attempt to get non-octet aligned data from BIT STRING");
|
||||
}
|
||||
|
||||
return Arrays.clone(data);
|
||||
}
|
||||
|
||||
public byte[] getBytes()
|
||||
{
|
||||
return derForm(data, padBits);
|
||||
}
|
||||
|
||||
public int getPadBits()
|
||||
{
|
||||
return padBits;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getString();
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return padBits ^ Arrays.hashCode(this.getBytes());
|
||||
}
|
||||
|
||||
protected boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1BitString))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1BitString other = (ASN1BitString)o;
|
||||
|
||||
return this.padBits == other.padBits
|
||||
&& Arrays.areEqual(this.getBytes(), other.getBytes());
|
||||
}
|
||||
|
||||
protected static byte[] derForm(byte[] data, int padBits)
|
||||
{
|
||||
byte[] rv = Arrays.clone(data);
|
||||
// DER requires pad bits be zero
|
||||
if (padBits > 0)
|
||||
{
|
||||
rv[data.length - 1] &= 0xff << padBits;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static ASN1BitString fromInputStream(int length, InputStream stream)
|
||||
throws IOException
|
||||
{
|
||||
if (length < 1)
|
||||
{
|
||||
throw new IllegalArgumentException("truncated BIT STRING detected");
|
||||
}
|
||||
|
||||
int padBits = stream.read();
|
||||
byte[] data = new byte[length - 1];
|
||||
|
||||
if (data.length != 0)
|
||||
{
|
||||
if (Streams.readFully(stream, data) != data.length)
|
||||
{
|
||||
throw new EOFException("EOF encountered in middle of BIT STRING");
|
||||
}
|
||||
|
||||
if (padBits > 0 && padBits < 8)
|
||||
{
|
||||
if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xff << padBits)))
|
||||
{
|
||||
return new DLBitString(data, padBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new DERBitString(data, padBits);
|
||||
}
|
||||
|
||||
public ASN1Primitive getLoadedObject()
|
||||
{
|
||||
return this.toASN1Primitive();
|
||||
}
|
||||
|
||||
ASN1Primitive toDERObject()
|
||||
{
|
||||
return new DERBitString(data, padBits);
|
||||
}
|
||||
|
||||
ASN1Primitive toDLObject()
|
||||
{
|
||||
return new DLBitString(data, padBits);
|
||||
}
|
||||
|
||||
abstract void encode(ASN1OutputStream out)
|
||||
throws IOException;
|
||||
}
|
@ -1,15 +1,220 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Public facade of ASN.1 Boolean data.
|
||||
* <p>
|
||||
* Use following to place a new instance of ASN.1 Boolean in your dataset:
|
||||
* <ul>
|
||||
* <li> ASN1Boolean.TRUE literal</li>
|
||||
* <li> ASN1Boolean.FALSE literal</li>
|
||||
* <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li>
|
||||
* <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public class ASN1Boolean
|
||||
extends DERBoolean
|
||||
extends ASN1Primitive
|
||||
{
|
||||
public ASN1Boolean(boolean value)
|
||||
private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
|
||||
private static final byte[] FALSE_VALUE = new byte[] { 0 };
|
||||
|
||||
private final byte[] value;
|
||||
|
||||
public static final ASN1Boolean FALSE = new ASN1Boolean(false);
|
||||
public static final ASN1Boolean TRUE = new ASN1Boolean(true);
|
||||
|
||||
/**
|
||||
* return a boolean from the passed in object.
|
||||
*
|
||||
* @param obj an ASN1Boolean or an object that can be converted into one.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
* @return an ASN1Boolean instance.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Boolean)
|
||||
{
|
||||
return (ASN1Boolean)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
byte[] enc = (byte[])obj;
|
||||
try
|
||||
{
|
||||
return (ASN1Boolean)fromByteArray(enc);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an ASN1Boolean from the passed in boolean.
|
||||
* @param value true or false depending on the ASN1Boolean wanted.
|
||||
* @return an ASN1Boolean instance.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
boolean value)
|
||||
{
|
||||
return (value ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* return an ASN1Boolean from the passed in value.
|
||||
* @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted.
|
||||
* @return an ASN1Boolean instance.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
int value)
|
||||
{
|
||||
super(value);
|
||||
return (value != 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
ASN1Boolean(byte[] value)
|
||||
// BEGIN android-added
|
||||
/**
|
||||
* return a ASN1Boolean from the passed in array.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
byte[] octets)
|
||||
{
|
||||
super(value);
|
||||
return (octets[0] != 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
// END android-added
|
||||
/**
|
||||
* return a Boolean from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
* @return an ASN1Boolean instance.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof ASN1Boolean)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
// BEGIN android-changed
|
||||
protected ASN1Boolean(
|
||||
// END android-changed
|
||||
byte[] value)
|
||||
{
|
||||
if (value.length != 1)
|
||||
{
|
||||
throw new IllegalArgumentException("byte value should have 1 byte in it");
|
||||
}
|
||||
|
||||
if (value[0] == 0)
|
||||
{
|
||||
this.value = FALSE_VALUE;
|
||||
}
|
||||
else if ((value[0] & 0xff) == 0xff)
|
||||
{
|
||||
this.value = TRUE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.value = Arrays.clone(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getInstance(boolean) method.
|
||||
* @param value true or false.
|
||||
*/
|
||||
// BEGIN android-changed
|
||||
protected ASN1Boolean(
|
||||
boolean value)
|
||||
// END android-changed
|
||||
{
|
||||
this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
|
||||
}
|
||||
|
||||
public boolean isTrue()
|
||||
{
|
||||
return (value[0] != 0);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.BOOLEAN, value);
|
||||
}
|
||||
|
||||
protected boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (o instanceof ASN1Boolean)
|
||||
{
|
||||
return (value[0] == ((ASN1Boolean)o).value[0]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return value[0];
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return (value[0] != 0) ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
||||
static ASN1Boolean fromOctetString(byte[] value)
|
||||
{
|
||||
if (value.length != 1)
|
||||
{
|
||||
throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
|
||||
}
|
||||
|
||||
if (value[0] == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if ((value[0] & 0xff) == 0xff)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1Boolean(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
/**
|
||||
* Basic interface to produce serialisers for ASN.1 encodings.
|
||||
*/
|
||||
public interface ASN1Encodable
|
||||
{
|
||||
/**
|
||||
* Return an object, possibly constructed, of ASN.1 primitives
|
||||
* @return an ASN.1 primitive.
|
||||
*/
|
||||
ASN1Primitive toASN1Primitive();
|
||||
}
|
||||
|
@ -1,8 +1,22 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
/**
|
||||
* Supported encoding formats.
|
||||
*/
|
||||
public interface ASN1Encoding
|
||||
{
|
||||
/**
|
||||
* DER - distinguished encoding rules.
|
||||
*/
|
||||
static final String DER = "DER";
|
||||
|
||||
/**
|
||||
* DL - definite length encoding.
|
||||
*/
|
||||
static final String DL = "DL";
|
||||
|
||||
/**
|
||||
* BER - basic encoding rules.
|
||||
*/
|
||||
static final String BER = "BER";
|
||||
}
|
||||
|
@ -1,22 +1,174 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Class representing the ASN.1 ENUMERATED type.
|
||||
*/
|
||||
public class ASN1Enumerated
|
||||
extends DEREnumerated
|
||||
extends ASN1Primitive
|
||||
{
|
||||
ASN1Enumerated(byte[] bytes)
|
||||
private final byte[] bytes;
|
||||
|
||||
/**
|
||||
* return an enumerated from the passed in object
|
||||
*
|
||||
* @param obj an ASN1Enumerated or an object that can be converted into one.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
* @return an ASN1Enumerated instance, or null.
|
||||
*/
|
||||
public static ASN1Enumerated getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Enumerated)
|
||||
{
|
||||
return (ASN1Enumerated)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1Enumerated)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Enumerated from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
* @return an ASN1Enumerated instance, or null.
|
||||
*/
|
||||
public static ASN1Enumerated getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof ASN1Enumerated)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromOctetString(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from int.
|
||||
*
|
||||
* @param value the value of this enumerated.
|
||||
*/
|
||||
public ASN1Enumerated(
|
||||
int value)
|
||||
{
|
||||
bytes = BigInteger.valueOf(value).toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from BigInteger
|
||||
*
|
||||
* @param value the value of this enumerated.
|
||||
*/
|
||||
public ASN1Enumerated(
|
||||
BigInteger value)
|
||||
{
|
||||
bytes = value.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from encoded BigInteger.
|
||||
*
|
||||
* @param bytes the value of this enumerated as an encoded BigInteger (signed).
|
||||
*/
|
||||
public ASN1Enumerated(
|
||||
byte[] bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public BigInteger getValue()
|
||||
{
|
||||
super(bytes);
|
||||
return new BigInteger(bytes);
|
||||
}
|
||||
|
||||
public ASN1Enumerated(BigInteger value)
|
||||
boolean isConstructed()
|
||||
{
|
||||
super(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
public ASN1Enumerated(int value)
|
||||
int encodedLength()
|
||||
{
|
||||
super(value);
|
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.ENUMERATED, bytes);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1Enumerated))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1Enumerated other = (ASN1Enumerated)o;
|
||||
|
||||
return Arrays.areEqual(this.bytes, other.bytes);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(bytes);
|
||||
}
|
||||
|
||||
private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
|
||||
|
||||
static ASN1Enumerated fromOctetString(byte[] enc)
|
||||
{
|
||||
if (enc.length > 1)
|
||||
{
|
||||
return new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
if (enc.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("ENUMERATED has zero length");
|
||||
}
|
||||
int value = enc[0] & 0xff;
|
||||
|
||||
if (value >= cache.length)
|
||||
{
|
||||
return new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
ASN1Enumerated possibleMatch = cache[value];
|
||||
|
||||
if (possibleMatch == null)
|
||||
{
|
||||
possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
return possibleMatch;
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,401 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.Strings;
|
||||
|
||||
/**
|
||||
* Base class representing the ASN.1 GeneralizedTime type.
|
||||
* <p>
|
||||
* The main difference between these and UTC time is a 4 digit year.
|
||||
* </p>
|
||||
*/
|
||||
public class ASN1GeneralizedTime
|
||||
extends DERGeneralizedTime
|
||||
extends ASN1Primitive
|
||||
{
|
||||
ASN1GeneralizedTime(byte[] bytes)
|
||||
private byte[] time;
|
||||
|
||||
/**
|
||||
* return a generalized time from the passed in object
|
||||
*
|
||||
* @param obj an ASN1GeneralizedTime or an object that can be converted into one.
|
||||
* @return an ASN1GeneralizedTime instance, or null.
|
||||
* @throws IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1GeneralizedTime getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1GeneralizedTime)
|
||||
{
|
||||
return (ASN1GeneralizedTime)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return a Generalized Time object from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @return an ASN1GeneralizedTime instance.
|
||||
* @throws IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1GeneralizedTime getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof ASN1GeneralizedTime)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
|
||||
* for local time, or Z+-HHMM on the end, for difference between local
|
||||
* time and UTC time. The fractional second amount f must consist of at
|
||||
* least one number with trailing zeroes removed.
|
||||
*
|
||||
* @param time the time string.
|
||||
* @throws IllegalArgumentException if String is an illegal format.
|
||||
*/
|
||||
public ASN1GeneralizedTime(
|
||||
String time)
|
||||
{
|
||||
this.time = Strings.toByteArray(time);
|
||||
try
|
||||
{
|
||||
this.getDate();
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor from a java.util.date object
|
||||
*
|
||||
* @param time a date object representing the time of interest.
|
||||
*/
|
||||
public ASN1GeneralizedTime(
|
||||
Date time)
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
|
||||
// END android-changed
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time));
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor from a java.util.date and Locale - you may need to use this if the default locale
|
||||
* doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
|
||||
*
|
||||
* @param time a date object representing the time of interest.
|
||||
* @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value.
|
||||
*/
|
||||
public ASN1GeneralizedTime(
|
||||
Date time,
|
||||
Locale locale)
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale);
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
|
||||
dateF.setCalendar(Calendar.getInstance(Locale.US));
|
||||
// END android-changed
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time));
|
||||
}
|
||||
|
||||
ASN1GeneralizedTime(
|
||||
byte[] bytes)
|
||||
{
|
||||
this.time = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time.
|
||||
*
|
||||
* @return The time string as it appeared in the encoded object.
|
||||
*/
|
||||
public String getTimeString()
|
||||
{
|
||||
return Strings.fromByteArray(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the time - always in the form of
|
||||
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
||||
* <p>
|
||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
||||
* however adding the "GMT" means we can just use:
|
||||
* <pre>
|
||||
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||||
* </pre>
|
||||
* To read in the time and get a date which is compatible with our local
|
||||
* time zone.
|
||||
* </p>
|
||||
* @return a String representation of the time.
|
||||
*/
|
||||
public String getTime()
|
||||
{
|
||||
String stime = Strings.fromByteArray(time);
|
||||
|
||||
//
|
||||
// standardise the format.
|
||||
//
|
||||
if (stime.charAt(stime.length() - 1) == 'Z')
|
||||
{
|
||||
return stime.substring(0, stime.length() - 1) + "GMT+00:00";
|
||||
}
|
||||
else
|
||||
{
|
||||
int signPos = stime.length() - 5;
|
||||
char sign = stime.charAt(signPos);
|
||||
if (sign == '-' || sign == '+')
|
||||
{
|
||||
return stime.substring(0, signPos)
|
||||
+ "GMT"
|
||||
+ stime.substring(signPos, signPos + 3)
|
||||
+ ":"
|
||||
+ stime.substring(signPos + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
signPos = stime.length() - 3;
|
||||
sign = stime.charAt(signPos);
|
||||
if (sign == '-' || sign == '+')
|
||||
{
|
||||
return stime.substring(0, signPos)
|
||||
+ "GMT"
|
||||
+ stime.substring(signPos)
|
||||
+ ":00";
|
||||
}
|
||||
}
|
||||
}
|
||||
return stime + calculateGMTOffset();
|
||||
}
|
||||
|
||||
private String calculateGMTOffset()
|
||||
{
|
||||
String sign = "+";
|
||||
TimeZone timeZone = TimeZone.getDefault();
|
||||
int offset = timeZone.getRawOffset();
|
||||
if (offset < 0)
|
||||
{
|
||||
sign = "-";
|
||||
offset = -offset;
|
||||
}
|
||||
int hours = offset / (60 * 60 * 1000);
|
||||
int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
|
||||
|
||||
try
|
||||
{
|
||||
if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
|
||||
{
|
||||
hours += sign.equals("+") ? 1 : -1;
|
||||
}
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
// we'll do our best and ignore daylight savings
|
||||
}
|
||||
|
||||
return "GMT" + sign + convert(hours) + ":" + convert(minutes);
|
||||
}
|
||||
|
||||
private String convert(int time)
|
||||
{
|
||||
if (time < 10)
|
||||
{
|
||||
return "0" + time;
|
||||
}
|
||||
|
||||
return Integer.toString(time);
|
||||
}
|
||||
|
||||
public Date getDate()
|
||||
throws ParseException
|
||||
{
|
||||
SimpleDateFormat dateF;
|
||||
String stime = Strings.fromByteArray(time);
|
||||
String d = stime;
|
||||
|
||||
if (stime.endsWith("Z"))
|
||||
{
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
else
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
}
|
||||
else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
|
||||
{
|
||||
d = this.getTime();
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
else
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
else
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
|
||||
// END android-changed
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
|
||||
}
|
||||
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
// java misinterprets extra digits as being milliseconds...
|
||||
String frac = d.substring(14);
|
||||
int index;
|
||||
for (index = 1; index < frac.length(); index++)
|
||||
{
|
||||
char ch = frac.charAt(index);
|
||||
if (!('0' <= ch && ch <= '9'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index - 1 > 3)
|
||||
{
|
||||
frac = frac.substring(0, 4) + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
else if (index - 1 == 1)
|
||||
{
|
||||
frac = frac.substring(0, index) + "00" + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
else if (index - 1 == 2)
|
||||
{
|
||||
frac = frac.substring(0, index) + "0" + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
}
|
||||
|
||||
return dateF.parse(d);
|
||||
}
|
||||
|
||||
private boolean hasFractionalSeconds()
|
||||
{
|
||||
for (int i = 0; i != time.length; i++)
|
||||
{
|
||||
if (time[i] == '.')
|
||||
{
|
||||
if (i == 14)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
super(bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
public ASN1GeneralizedTime(Date time)
|
||||
int encodedLength()
|
||||
{
|
||||
super(time);
|
||||
int length = time.length;
|
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.GENERALIZED_TIME, time);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1GeneralizedTime))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time);
|
||||
}
|
||||
|
||||
public ASN1GeneralizedTime(String time)
|
||||
public int hashCode()
|
||||
{
|
||||
super(time);
|
||||
return Arrays.hashCode(time);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,157 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Class representing the ASN.1 INTEGER type.
|
||||
*/
|
||||
public class ASN1Integer
|
||||
extends DERInteger
|
||||
extends ASN1Primitive
|
||||
{
|
||||
ASN1Integer(byte[] bytes)
|
||||
private final byte[] bytes;
|
||||
|
||||
/**
|
||||
* return an integer from the passed in object
|
||||
*
|
||||
* @param obj an ASN1Integer or an object that can be converted into one.
|
||||
* @throws IllegalArgumentException if the object cannot be converted.
|
||||
* @return an ASN1Integer instance.
|
||||
*/
|
||||
public static ASN1Integer getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Integer)
|
||||
{
|
||||
return (ASN1Integer)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1Integer)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Integer from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @throws IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
* @return an ASN1Integer instance.
|
||||
*/
|
||||
public static ASN1Integer getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof ASN1Integer)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
public ASN1Integer(
|
||||
long value)
|
||||
{
|
||||
super(bytes);
|
||||
bytes = BigInteger.valueOf(value).toByteArray();
|
||||
}
|
||||
|
||||
public ASN1Integer(BigInteger value)
|
||||
public ASN1Integer(
|
||||
BigInteger value)
|
||||
{
|
||||
super(value);
|
||||
bytes = value.toByteArray();
|
||||
}
|
||||
|
||||
public ASN1Integer(long value)
|
||||
public ASN1Integer(
|
||||
byte[] bytes)
|
||||
{
|
||||
super(value);
|
||||
this(bytes, true);
|
||||
}
|
||||
|
||||
ASN1Integer(byte[] bytes, boolean clone)
|
||||
{
|
||||
this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
|
||||
}
|
||||
|
||||
public BigInteger getValue()
|
||||
{
|
||||
return new BigInteger(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* in some cases positive values get crammed into a space,
|
||||
* that's not quite big enough...
|
||||
* @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned.
|
||||
*/
|
||||
public BigInteger getPositiveValue()
|
||||
{
|
||||
return new BigInteger(1, bytes);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.INTEGER, bytes);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
for (int i = 0; i != bytes.length; i++)
|
||||
{
|
||||
value ^= (bytes[i] & 0xff) << (i % 4);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1Integer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1Integer other = (ASN1Integer)o;
|
||||
|
||||
return Arrays.areEqual(bytes, other.bytes);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getValue().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
/**
|
||||
* General interface implemented by ASN.1 STRING objects.
|
||||
*/
|
||||
public interface ASN1String
|
||||
{
|
||||
/**
|
||||
* Return a Java String representation of this STRING type's content.
|
||||
* @return a Java String representation of this STRING.
|
||||
*/
|
||||
public String getString();
|
||||
}
|
||||
|
@ -1,22 +1,328 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.Strings;
|
||||
|
||||
/**
|
||||
- * UTC time object.
|
||||
* Internal facade of {@link ASN1UTCTime}.
|
||||
* <p>
|
||||
* This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC.
|
||||
* <p>
|
||||
* <hr>
|
||||
* <p><b>X.690</b></p>
|
||||
* <p><b>11: Restrictions on BER employed by both CER and DER</b></p>
|
||||
* <p><b>11.8 UTCTime </b></p>
|
||||
* <b>11.8.1</b> The encoding shall terminate with "Z",
|
||||
* as described in the ITU-T X.680 | ISO/IEC 8824-1 clause on UTCTime.
|
||||
* <p>
|
||||
* <b>11.8.2</b> The seconds element shall always be present.
|
||||
* <p>
|
||||
* <b>11.8.3</b> Midnight (GMT) shall be represented in the form:
|
||||
* <blockquote>
|
||||
* "YYMMDD000000Z"
|
||||
* </blockquote>
|
||||
* where "YYMMDD" represents the day following the midnight in question.
|
||||
*/
|
||||
public class ASN1UTCTime
|
||||
extends DERUTCTime
|
||||
extends ASN1Primitive
|
||||
{
|
||||
ASN1UTCTime(byte[] bytes)
|
||||
private byte[] time;
|
||||
|
||||
/**
|
||||
* return an UTC Time from the passed in object.
|
||||
*
|
||||
* @param obj an ASN1UTCTime or an object that can be converted into one.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
* @return an ASN1UTCTime instance, or null.
|
||||
*/
|
||||
public static ASN1UTCTime getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1UTCTime)
|
||||
{
|
||||
return (ASN1UTCTime)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1UTCTime)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an UTC Time from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
* @return an ASN1UTCTime instance, or null.
|
||||
*/
|
||||
public static ASN1UTCTime getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Object o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof ASN1UTCTime)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
|
||||
* never encoded. When you're creating one of these objects from scratch, that's
|
||||
* what you want to use, otherwise we'll try to deal with whatever gets read from
|
||||
* the input stream... (this is why the input format is different from the getTime()
|
||||
* method output).
|
||||
* <p>
|
||||
*
|
||||
* @param time the time string.
|
||||
*/
|
||||
public ASN1UTCTime(
|
||||
String time)
|
||||
{
|
||||
this.time = Strings.toByteArray(time);
|
||||
try
|
||||
{
|
||||
this.getDate();
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base constructor from a java.util.date object
|
||||
* @param time the Date to build the time from.
|
||||
*/
|
||||
public ASN1UTCTime(
|
||||
Date time)
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US);
|
||||
// END android-changed
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
|
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time));
|
||||
}
|
||||
|
||||
/**
|
||||
* Base constructor from a java.util.date and Locale - you may need to use this if the default locale
|
||||
* doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations.
|
||||
*
|
||||
* @param time a date object representing the time of interest.
|
||||
* @param locale an appropriate Locale for producing an ASN.1 UTCTime value.
|
||||
*/
|
||||
public ASN1UTCTime(
|
||||
Date time,
|
||||
Locale locale)
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale);
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US);
|
||||
dateF.setCalendar(Calendar.getInstance(locale));
|
||||
// END android-changed
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
|
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time));
|
||||
}
|
||||
|
||||
ASN1UTCTime(
|
||||
byte[] time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the time as a date based on whatever a 2 digit year will return. For
|
||||
* standardised processing use getAdjustedDate().
|
||||
*
|
||||
* @return the resulting date
|
||||
* @exception ParseException if the date string cannot be parsed.
|
||||
*/
|
||||
public Date getDate()
|
||||
throws ParseException
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz");
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz", Locale.US);
|
||||
// END android-changed
|
||||
|
||||
return dateF.parse(getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* return the time as an adjusted date
|
||||
* in the range of 1950 - 2049.
|
||||
*
|
||||
* @return a date in the range of 1950 to 2049.
|
||||
* @exception ParseException if the date string cannot be parsed.
|
||||
*/
|
||||
public Date getAdjustedDate()
|
||||
throws ParseException
|
||||
{
|
||||
// BEGIN android-changed
|
||||
// Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US);
|
||||
// END android-changed
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
|
||||
return dateF.parse(getAdjustedTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* return the time - always in the form of
|
||||
* YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
||||
* <p>
|
||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
||||
* however adding the "GMT" means we can just use:
|
||||
* <pre>
|
||||
* dateF = new SimpleDateFormat("yyMMddHHmmssz");
|
||||
* </pre>
|
||||
* To read in the time and get a date which is compatible with our local
|
||||
* time zone.
|
||||
* <p>
|
||||
* <b>Note:</b> In some cases, due to the local date processing, this
|
||||
* may lead to unexpected results. If you want to stick the normal
|
||||
* convention of 1950 to 2049 use the getAdjustedTime() method.
|
||||
*/
|
||||
public String getTime()
|
||||
{
|
||||
String stime = Strings.fromByteArray(time);
|
||||
|
||||
//
|
||||
// standardise the format.
|
||||
//
|
||||
if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
|
||||
{
|
||||
if (stime.length() == 11)
|
||||
{
|
||||
return stime.substring(0, 10) + "00GMT+00:00";
|
||||
}
|
||||
else
|
||||
{
|
||||
return stime.substring(0, 12) + "GMT+00:00";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = stime.indexOf('-');
|
||||
if (index < 0)
|
||||
{
|
||||
index = stime.indexOf('+');
|
||||
}
|
||||
String d = stime;
|
||||
|
||||
if (index == stime.length() - 3)
|
||||
{
|
||||
d += "00";
|
||||
}
|
||||
|
||||
if (index == 10)
|
||||
{
|
||||
return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return a time string as an adjusted date with a 4 digit year. This goes
|
||||
* in the range of 1950 - 2049.
|
||||
*/
|
||||
public String getAdjustedTime()
|
||||
{
|
||||
String d = this.getTime();
|
||||
|
||||
if (d.charAt(0) < '5')
|
||||
{
|
||||
return "20" + d;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "19" + d;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
int length = time.length;
|
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
super(bytes);
|
||||
out.write(BERTags.UTC_TIME);
|
||||
|
||||
int length = time.length;
|
||||
|
||||
out.writeLength(length);
|
||||
|
||||
for (int i = 0; i != length; i++)
|
||||
{
|
||||
out.write((byte)time[i]);
|
||||
}
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof ASN1UTCTime))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Arrays.areEqual(time, ((ASN1UTCTime)o).time);
|
||||
}
|
||||
|
||||
public ASN1UTCTime(Date time)
|
||||
public int hashCode()
|
||||
{
|
||||
super(time);
|
||||
return Arrays.hashCode(time);
|
||||
}
|
||||
|
||||
public ASN1UTCTime(String time)
|
||||
public String toString()
|
||||
{
|
||||
super(time);
|
||||
return Strings.fromByteArray(time);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,114 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An indefinite-length encoding version of an application specific object.
|
||||
*/
|
||||
public class BERApplicationSpecific
|
||||
extends DERApplicationSpecific
|
||||
extends ASN1ApplicationSpecific
|
||||
{
|
||||
BERApplicationSpecific(
|
||||
boolean isConstructed,
|
||||
int tag,
|
||||
byte[] octets)
|
||||
{
|
||||
super(isConstructed, tag, octets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application specific object with a tagging of explicit/constructed.
|
||||
*
|
||||
* @param tag the tag number for this object.
|
||||
* @param object the object to be contained.
|
||||
*/
|
||||
public BERApplicationSpecific(
|
||||
int tag,
|
||||
ASN1Encodable object)
|
||||
throws IOException
|
||||
{
|
||||
this(true, tag, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application specific object with the tagging style given by the value of constructed.
|
||||
*
|
||||
* @param constructed true if the object is constructed.
|
||||
* @param tag the tag number for this object.
|
||||
* @param object the object to be contained.
|
||||
*/
|
||||
public BERApplicationSpecific(
|
||||
boolean constructed,
|
||||
int tag,
|
||||
ASN1Encodable object)
|
||||
throws IOException
|
||||
{
|
||||
super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object));
|
||||
}
|
||||
|
||||
private static byte[] getEncoding(boolean explicit, ASN1Encodable object)
|
||||
throws IOException
|
||||
{
|
||||
byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.BER);
|
||||
|
||||
if (explicit)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
int lenBytes = getLengthOfHeader(data);
|
||||
byte[] tmp = new byte[data.length - lenBytes];
|
||||
System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an application specific object which is marked as constructed
|
||||
*
|
||||
* @param tagNo the tag number for this object.
|
||||
* @param vec the objects making up the application specific object.
|
||||
*/
|
||||
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
|
||||
{
|
||||
super(tagNo, vec);
|
||||
super(true, tagNo, getEncodedVector(vec));
|
||||
}
|
||||
|
||||
private static byte[] getEncodedVector(ASN1EncodableVector vec)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
for (int i = 0; i != vec.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.BER));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new ASN1ParsingException("malformed object: " + e, e);
|
||||
}
|
||||
}
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
|
||||
*/
|
||||
void encode(ASN1OutputStream out) throws IOException
|
||||
{
|
||||
int classBits = BERTags.APPLICATION;
|
||||
if (isConstructed)
|
||||
{
|
||||
classBits |= BERTags.CONSTRUCTED;
|
||||
}
|
||||
|
||||
out.writeTag(classBits, tag);
|
||||
out.write(0x80);
|
||||
out.write(octets);
|
||||
out.write(0x00);
|
||||
out.write(0x00);
|
||||
}
|
||||
}
|
||||
|
@ -1,196 +1,22 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* @deprecated use ASN1Boolean
|
||||
*/
|
||||
public class DERBoolean
|
||||
extends ASN1Primitive
|
||||
extends ASN1Boolean
|
||||
{
|
||||
private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
|
||||
private static final byte[] FALSE_VALUE = new byte[] { 0 };
|
||||
|
||||
// BEGIN android-changed
|
||||
final private byte[] value;
|
||||
// END android-changed
|
||||
|
||||
public static final ASN1Boolean FALSE = new ASN1Boolean(false);
|
||||
public static final ASN1Boolean TRUE = new ASN1Boolean(true);
|
||||
|
||||
|
||||
/**
|
||||
* return a boolean from the passed in object.
|
||||
*
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Boolean)
|
||||
{
|
||||
return (ASN1Boolean)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof DERBoolean)
|
||||
{
|
||||
return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return a ASN1Boolean from the passed in boolean.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
boolean value)
|
||||
{
|
||||
return (value ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a ASN1Boolean from the passed in boolean.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
int value)
|
||||
{
|
||||
return (value != 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
// BEGIN android-added
|
||||
/**
|
||||
* return a DERBoolean from the passed in array.
|
||||
*/
|
||||
public static DERBoolean getInstance(
|
||||
byte[] octets)
|
||||
{
|
||||
return (octets[0] != 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
// END android-added
|
||||
/**
|
||||
* return a Boolean from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1Boolean getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DERBoolean)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
// BEGIN android-changed
|
||||
protected DERBoolean(
|
||||
// END android-changed
|
||||
byte[] value)
|
||||
{
|
||||
if (value.length != 1)
|
||||
{
|
||||
throw new IllegalArgumentException("byte value should have 1 byte in it");
|
||||
}
|
||||
|
||||
if (value[0] == 0)
|
||||
{
|
||||
this.value = FALSE_VALUE;
|
||||
}
|
||||
else if (value[0] == 0xff)
|
||||
{
|
||||
this.value = TRUE_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.value = Arrays.clone(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getInstance(boolean) method.
|
||||
* @param value
|
||||
*/
|
||||
// BEGIN android-changed
|
||||
protected DERBoolean(
|
||||
boolean value)
|
||||
// END android-changed
|
||||
public DERBoolean(boolean value)
|
||||
{
|
||||
this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
|
||||
super(value);
|
||||
}
|
||||
|
||||
public boolean isTrue()
|
||||
DERBoolean(byte[] value)
|
||||
{
|
||||
return (value[0] != 0);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.BOOLEAN, value);
|
||||
}
|
||||
|
||||
protected boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if ((o == null) || !(o instanceof DERBoolean))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (value[0] == ((DERBoolean)o).value[0]);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return value[0];
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return (value[0] != 0) ? "TRUE" : "FALSE";
|
||||
}
|
||||
|
||||
static ASN1Boolean fromOctetString(byte[] value)
|
||||
{
|
||||
if (value.length != 1)
|
||||
{
|
||||
throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
|
||||
}
|
||||
|
||||
if (value[0] == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (value[0] == 0xff)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1Boolean(value);
|
||||
}
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
@ -1,170 +1,37 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Use ASN1Enumerated instead of this.
|
||||
* @deprecated Use ASN1Enumerated instead of this.
|
||||
*/
|
||||
public class DEREnumerated
|
||||
extends ASN1Primitive
|
||||
extends ASN1Enumerated
|
||||
{
|
||||
byte[] bytes;
|
||||
|
||||
/**
|
||||
* return an integer from the passed in object
|
||||
*
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1Enumerated getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Enumerated)
|
||||
{
|
||||
return (ASN1Enumerated)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof DEREnumerated)
|
||||
{
|
||||
return new ASN1Enumerated(((DEREnumerated)obj).getValue());
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1Enumerated)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Enumerated from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1Enumerated getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DEREnumerated)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromOctetString(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bytes the value of this enumerated as an encoded BigInteger (signed).
|
||||
* @deprecated use ASN1Enumerated
|
||||
*/
|
||||
public DEREnumerated(
|
||||
int value)
|
||||
DEREnumerated(byte[] bytes)
|
||||
{
|
||||
bytes = BigInteger.valueOf(value).toByteArray();
|
||||
super(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the value of this enumerated.
|
||||
* @deprecated use ASN1Enumerated
|
||||
*/
|
||||
public DEREnumerated(
|
||||
BigInteger value)
|
||||
public DEREnumerated(BigInteger value)
|
||||
{
|
||||
bytes = value.toByteArray();
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the value of this enumerated.
|
||||
* @deprecated use ASN1Enumerated
|
||||
*/
|
||||
public DEREnumerated(
|
||||
byte[] bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public BigInteger getValue()
|
||||
{
|
||||
return new BigInteger(bytes);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
public DEREnumerated(int value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.ENUMERATED, bytes);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof DEREnumerated))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DEREnumerated other = (DEREnumerated)o;
|
||||
|
||||
return Arrays.areEqual(this.bytes, other.bytes);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(bytes);
|
||||
}
|
||||
|
||||
private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
|
||||
|
||||
static ASN1Enumerated fromOctetString(byte[] enc)
|
||||
{
|
||||
if (enc.length > 1)
|
||||
{
|
||||
return new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
if (enc.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("ENUMERATED has zero length");
|
||||
}
|
||||
int value = enc[0] & 0xff;
|
||||
|
||||
if (value >= cache.length)
|
||||
{
|
||||
return new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
ASN1Enumerated possibleMatch = cache[value];
|
||||
|
||||
if (possibleMatch == null)
|
||||
{
|
||||
possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
|
||||
}
|
||||
|
||||
return possibleMatch;
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
@ -1,350 +1,28 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.Strings;
|
||||
|
||||
/**
|
||||
* Generalized time object.
|
||||
* DER Generalized time object.
|
||||
*/
|
||||
public class DERGeneralizedTime
|
||||
extends ASN1Primitive
|
||||
extends ASN1GeneralizedTime
|
||||
{
|
||||
private byte[] time;
|
||||
|
||||
/**
|
||||
* return a generalized time from the passed in object
|
||||
*
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1GeneralizedTime getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1GeneralizedTime)
|
||||
{
|
||||
return (ASN1GeneralizedTime)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof DERGeneralizedTime)
|
||||
{
|
||||
return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time);
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return a Generalized Time object from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1GeneralizedTime getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DERGeneralizedTime)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
|
||||
* for local time, or Z+-HHMM on the end, for difference between local
|
||||
* time and UTC time. The fractional second amount f must consist of at
|
||||
* least one number with trailing zeroes removed.
|
||||
*
|
||||
* @param time the time string.
|
||||
* @exception IllegalArgumentException if String is an illegal format.
|
||||
*/
|
||||
public DERGeneralizedTime(
|
||||
String time)
|
||||
{
|
||||
this.time = Strings.toByteArray(time);
|
||||
try
|
||||
{
|
||||
this.getDate();
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base constructor from a java.util.date object
|
||||
*/
|
||||
public DERGeneralizedTime(
|
||||
Date time)
|
||||
{
|
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
|
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time));
|
||||
}
|
||||
|
||||
DERGeneralizedTime(
|
||||
byte[] bytes)
|
||||
{
|
||||
this.time = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time.
|
||||
* @return The time string as it appeared in the encoded object.
|
||||
*/
|
||||
public String getTimeString()
|
||||
{
|
||||
return Strings.fromByteArray(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the time - always in the form of
|
||||
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
||||
* <p>
|
||||
* Normally in a certificate we would expect "Z" rather than "GMT",
|
||||
* however adding the "GMT" means we can just use:
|
||||
* <pre>
|
||||
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||||
* </pre>
|
||||
* To read in the time and get a date which is compatible with our local
|
||||
* time zone.
|
||||
*/
|
||||
public String getTime()
|
||||
{
|
||||
String stime = Strings.fromByteArray(time);
|
||||
|
||||
//
|
||||
// standardise the format.
|
||||
//
|
||||
if (stime.charAt(stime.length() - 1) == 'Z')
|
||||
{
|
||||
return stime.substring(0, stime.length() - 1) + "GMT+00:00";
|
||||
}
|
||||
else
|
||||
{
|
||||
int signPos = stime.length() - 5;
|
||||
char sign = stime.charAt(signPos);
|
||||
if (sign == '-' || sign == '+')
|
||||
{
|
||||
return stime.substring(0, signPos)
|
||||
+ "GMT"
|
||||
+ stime.substring(signPos, signPos + 3)
|
||||
+ ":"
|
||||
+ stime.substring(signPos + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
signPos = stime.length() - 3;
|
||||
sign = stime.charAt(signPos);
|
||||
if (sign == '-' || sign == '+')
|
||||
{
|
||||
return stime.substring(0, signPos)
|
||||
+ "GMT"
|
||||
+ stime.substring(signPos)
|
||||
+ ":00";
|
||||
}
|
||||
}
|
||||
}
|
||||
return stime + calculateGMTOffset();
|
||||
}
|
||||
|
||||
private String calculateGMTOffset()
|
||||
DERGeneralizedTime(byte[] bytes)
|
||||
{
|
||||
String sign = "+";
|
||||
TimeZone timeZone = TimeZone.getDefault();
|
||||
int offset = timeZone.getRawOffset();
|
||||
if (offset < 0)
|
||||
{
|
||||
sign = "-";
|
||||
offset = -offset;
|
||||
}
|
||||
int hours = offset / (60 * 60 * 1000);
|
||||
int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
|
||||
|
||||
try
|
||||
{
|
||||
if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
|
||||
{
|
||||
hours += sign.equals("+") ? 1 : -1;
|
||||
}
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
// we'll do our best and ignore daylight savings
|
||||
}
|
||||
|
||||
return "GMT" + sign + convert(hours) + ":" + convert(minutes);
|
||||
super(bytes);
|
||||
}
|
||||
|
||||
private String convert(int time)
|
||||
public DERGeneralizedTime(Date time)
|
||||
{
|
||||
if (time < 10)
|
||||
{
|
||||
return "0" + time;
|
||||
}
|
||||
|
||||
return Integer.toString(time);
|
||||
}
|
||||
|
||||
public Date getDate()
|
||||
throws ParseException
|
||||
{
|
||||
SimpleDateFormat dateF;
|
||||
String stime = Strings.fromByteArray(time);
|
||||
String d = stime;
|
||||
|
||||
if (stime.endsWith("Z"))
|
||||
{
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
|
||||
}
|
||||
else
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
}
|
||||
else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
|
||||
{
|
||||
d = this.getTime();
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
|
||||
}
|
||||
else
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
|
||||
}
|
||||
else
|
||||
{
|
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
}
|
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
|
||||
}
|
||||
|
||||
if (hasFractionalSeconds())
|
||||
{
|
||||
// java misinterprets extra digits as being milliseconds...
|
||||
String frac = d.substring(14);
|
||||
int index;
|
||||
for (index = 1; index < frac.length(); index++)
|
||||
{
|
||||
char ch = frac.charAt(index);
|
||||
if (!('0' <= ch && ch <= '9'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index - 1 > 3)
|
||||
{
|
||||
frac = frac.substring(0, 4) + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
else if (index - 1 == 1)
|
||||
{
|
||||
frac = frac.substring(0, index) + "00" + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
else if (index - 1 == 2)
|
||||
{
|
||||
frac = frac.substring(0, index) + "0" + frac.substring(index);
|
||||
d = d.substring(0, 14) + frac;
|
||||
}
|
||||
}
|
||||
|
||||
return dateF.parse(d);
|
||||
super(time);
|
||||
}
|
||||
|
||||
private boolean hasFractionalSeconds()
|
||||
public DERGeneralizedTime(String time)
|
||||
{
|
||||
for (int i = 0; i != time.length; i++)
|
||||
{
|
||||
if (time[i] == '.')
|
||||
{
|
||||
if (i == 14)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
super(time);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
int length = time.length;
|
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.GENERALIZED_TIME, time);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof DERGeneralizedTime))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(time);
|
||||
}
|
||||
// TODO: create proper DER encoding.
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.Strings;
|
||||
|
||||
public class DERGraphicString
|
||||
extends ASN1Primitive
|
||||
implements ASN1String
|
||||
{
|
||||
private final byte[] string;
|
||||
|
||||
/**
|
||||
* return a Graphic String from the passed in object
|
||||
*
|
||||
* @param obj a DERGraphicString or an object that can be converted into one.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
* @return a DERGraphicString instance, or null.
|
||||
*/
|
||||
public static DERGraphicString getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof DERGraphicString)
|
||||
{
|
||||
return (DERGraphicString)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (DERGraphicString)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return a Graphic String from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
* @return a DERGraphicString instance, or null.
|
||||
*/
|
||||
public static DERGraphicString getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DERGraphicString)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new DERGraphicString(((ASN1OctetString)o).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* basic constructor - with bytes.
|
||||
* @param string the byte encoding of the characters making up the string.
|
||||
*/
|
||||
public DERGraphicString(
|
||||
byte[] string)
|
||||
{
|
||||
this.string = Arrays.clone(string);
|
||||
}
|
||||
|
||||
public byte[] getOctets()
|
||||
{
|
||||
return Arrays.clone(string);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.GRAPHIC_STRING, string);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(string);
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof DERGraphicString))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DERGraphicString s = (DERGraphicString)o;
|
||||
|
||||
return Arrays.areEqual(string, s.string);
|
||||
}
|
||||
|
||||
public String getString()
|
||||
{
|
||||
return Strings.fromByteArray(string);
|
||||
}
|
||||
}
|
@ -1,160 +1,30 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Use ASN1Integer instead of this,
|
||||
* @deprecated Use ASN1Integer instead of this,
|
||||
*/
|
||||
public class DERInteger
|
||||
extends ASN1Primitive
|
||||
extends ASN1Integer
|
||||
{
|
||||
byte[] bytes;
|
||||
|
||||
/**
|
||||
* return an integer from the passed in object
|
||||
*
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1Integer getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Integer)
|
||||
{
|
||||
return (ASN1Integer)obj;
|
||||
}
|
||||
if (obj instanceof DERInteger)
|
||||
{
|
||||
return new ASN1Integer((((DERInteger)obj).getValue()));
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1Integer)fromByteArray((byte[])obj);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Integer from a tagged object.
|
||||
* Constructor from a byte array containing a signed representation of the number.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1Integer getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DERInteger)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use ASN1Integer constructor
|
||||
*/
|
||||
public DERInteger(
|
||||
long value)
|
||||
{
|
||||
bytes = BigInteger.valueOf(value).toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use ASN1Integer constructor
|
||||
* @param bytes a byte array containing the signed number.A copy is made of the byte array.
|
||||
*/
|
||||
public DERInteger(
|
||||
BigInteger value)
|
||||
public DERInteger(byte[] bytes)
|
||||
{
|
||||
bytes = value.toByteArray();
|
||||
super(bytes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use ASN1Integer constructor
|
||||
*/
|
||||
public DERInteger(
|
||||
byte[] bytes)
|
||||
public DERInteger(BigInteger value)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public BigInteger getValue()
|
||||
{
|
||||
return new BigInteger(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* in some cases positive values get crammed into a space,
|
||||
* that's not quite big enough...
|
||||
*/
|
||||
public BigInteger getPositiveValue()
|
||||
{
|
||||
return new BigInteger(1, bytes);
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
{
|
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeEncoded(BERTags.INTEGER, bytes);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
for (int i = 0; i != bytes.length; i++)
|
||||
{
|
||||
value ^= (bytes[i] & 0xff) << (i % 4);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof DERInteger))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DERInteger other = (DERInteger)o;
|
||||
|
||||
return Arrays.areEqual(bytes, other.bytes);
|
||||
super(value);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
public DERInteger(long value)
|
||||
{
|
||||
return getValue().toString();
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
@ -1,458 +1,24 @@
|
||||
package org.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
/**
|
||||
* Use ASN1ObjectIdentifier instead of this,
|
||||
*
|
||||
* @deprecated Use ASN1ObjectIdentifier instead of this,
|
||||
*/
|
||||
public class DERObjectIdentifier
|
||||
extends ASN1Primitive
|
||||
extends ASN1ObjectIdentifier
|
||||
{
|
||||
String identifier;
|
||||
|
||||
private byte[] body;
|
||||
|
||||
/**
|
||||
* return an OID from the passed in object
|
||||
*
|
||||
* @throws IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1ObjectIdentifier getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1ObjectIdentifier)
|
||||
{
|
||||
return (ASN1ObjectIdentifier)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof DERObjectIdentifier)
|
||||
{
|
||||
return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
|
||||
}
|
||||
|
||||
if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
|
||||
{
|
||||
return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
|
||||
}
|
||||
|
||||
if (obj instanceof byte[])
|
||||
{
|
||||
byte[] enc = (byte[])obj;
|
||||
if (enc[0] == BERTags.OBJECT_IDENTIFIER)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (ASN1ObjectIdentifier)fromByteArray(enc);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // TODO: this really shouldn't be supported here...
|
||||
return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Object Identifier from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @throws IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1ObjectIdentifier getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
ASN1Primitive o = obj.getObject();
|
||||
|
||||
if (explicit || o instanceof DERObjectIdentifier)
|
||||
{
|
||||
return getInstance(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
|
||||
}
|
||||
}
|
||||
|
||||
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
|
||||
|
||||
DERObjectIdentifier(
|
||||
byte[] bytes)
|
||||
public DERObjectIdentifier(String identifier)
|
||||
{
|
||||
StringBuffer objId = new StringBuffer();
|
||||
long value = 0;
|
||||
BigInteger bigValue = null;
|
||||
boolean first = true;
|
||||
|
||||
for (int i = 0; i != bytes.length; i++)
|
||||
{
|
||||
int b = bytes[i] & 0xff;
|
||||
|
||||
if (value <= LONG_LIMIT)
|
||||
{
|
||||
value += (b & 0x7f);
|
||||
if ((b & 0x80) == 0) // end of number reached
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
if (value < 40)
|
||||
{
|
||||
objId.append('0');
|
||||
}
|
||||
else if (value < 80)
|
||||
{
|
||||
objId.append('1');
|
||||
value -= 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
objId.append('2');
|
||||
value -= 80;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
objId.append('.');
|
||||
objId.append(value);
|
||||
value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value <<= 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bigValue == null)
|
||||
{
|
||||
bigValue = BigInteger.valueOf(value);
|
||||
}
|
||||
bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
|
||||
if ((b & 0x80) == 0)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
objId.append('2');
|
||||
bigValue = bigValue.subtract(BigInteger.valueOf(80));
|
||||
first = false;
|
||||
}
|
||||
|
||||
objId.append('.');
|
||||
objId.append(bigValue);
|
||||
bigValue = null;
|
||||
value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bigValue = bigValue.shiftLeft(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BEGIN android-changed
|
||||
/*
|
||||
* Intern the identifier so there aren't hundreds of duplicates
|
||||
* (in practice).
|
||||
*/
|
||||
this.identifier = objId.toString().intern();
|
||||
// END android-changed
|
||||
this.body = Arrays.clone(bytes);
|
||||
super(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use ASN1ObjectIdentifier constructor.
|
||||
*/
|
||||
public DERObjectIdentifier(
|
||||
String identifier)
|
||||
DERObjectIdentifier(byte[] bytes)
|
||||
{
|
||||
if (identifier == null)
|
||||
{
|
||||
throw new IllegalArgumentException("'identifier' cannot be null");
|
||||
}
|
||||
if (!isValidIdentifier(identifier))
|
||||
{
|
||||
throw new IllegalArgumentException("string " + identifier + " not an OID");
|
||||
}
|
||||
|
||||
// BEGIN android-changed
|
||||
/*
|
||||
* Intern the identifier so there aren't hundreds of duplicates
|
||||
* (in practice).
|
||||
*/
|
||||
this.identifier = identifier.intern();
|
||||
// END android-changed
|
||||
super(bytes);
|
||||
}
|
||||
|
||||
DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
|
||||
DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
|
||||
{
|
||||
if (!isValidBranchID(branchID, 0))
|
||||
{
|
||||
throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
|
||||
}
|
||||
|
||||
this.identifier = oid.getId() + "." + branchID;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
|
||||
private void writeField(
|
||||
ByteArrayOutputStream out,
|
||||
long fieldValue)
|
||||
{
|
||||
byte[] result = new byte[9];
|
||||
int pos = 8;
|
||||
result[pos] = (byte)((int)fieldValue & 0x7f);
|
||||
while (fieldValue >= (1L << 7))
|
||||
{
|
||||
fieldValue >>= 7;
|
||||
result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
|
||||
}
|
||||
out.write(result, pos, 9 - pos);
|
||||
}
|
||||
|
||||
private void writeField(
|
||||
ByteArrayOutputStream out,
|
||||
BigInteger fieldValue)
|
||||
{
|
||||
int byteCount = (fieldValue.bitLength() + 6) / 7;
|
||||
if (byteCount == 0)
|
||||
{
|
||||
out.write(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
BigInteger tmpValue = fieldValue;
|
||||
byte[] tmp = new byte[byteCount];
|
||||
for (int i = byteCount - 1; i >= 0; i--)
|
||||
{
|
||||
tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
|
||||
tmpValue = tmpValue.shiftRight(7);
|
||||
}
|
||||
tmp[byteCount - 1] &= 0x7f;
|
||||
out.write(tmp, 0, tmp.length);
|
||||
}
|
||||
}
|
||||
|
||||
private void doOutput(ByteArrayOutputStream aOut)
|
||||
{
|
||||
OIDTokenizer tok = new OIDTokenizer(identifier);
|
||||
int first = Integer.parseInt(tok.nextToken()) * 40;
|
||||
|
||||
String secondToken = tok.nextToken();
|
||||
if (secondToken.length() <= 18)
|
||||
{
|
||||
writeField(aOut, first + Long.parseLong(secondToken));
|
||||
}
|
||||
else
|
||||
{
|
||||
writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
|
||||
}
|
||||
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
String token = tok.nextToken();
|
||||
if (token.length() <= 18)
|
||||
{
|
||||
writeField(aOut, Long.parseLong(token));
|
||||
}
|
||||
else
|
||||
{
|
||||
writeField(aOut, new BigInteger(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized byte[] getBody()
|
||||
{
|
||||
if (body == null)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
doOutput(bOut);
|
||||
|
||||
body = bOut.toByteArray();
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
boolean isConstructed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int encodedLength()
|
||||
throws IOException
|
||||
{
|
||||
int length = getBody().length;
|
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length;
|
||||
}
|
||||
|
||||
void encode(
|
||||
ASN1OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
byte[] enc = getBody();
|
||||
|
||||
out.write(BERTags.OBJECT_IDENTIFIER);
|
||||
out.writeLength(enc.length);
|
||||
out.write(enc);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return identifier.hashCode();
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
ASN1Primitive o)
|
||||
{
|
||||
if (!(o instanceof DERObjectIdentifier))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return identifier.equals(((DERObjectIdentifier)o).identifier);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getId();
|
||||
}
|
||||
|
||||
private static boolean isValidBranchID(
|
||||
String branchID, int start)
|
||||
{
|
||||
boolean periodAllowed = false;
|
||||
|
||||
int pos = branchID.length();
|
||||
while (--pos >= start)
|
||||
{
|
||||
char ch = branchID.charAt(pos);
|
||||
|
||||
// TODO Leading zeroes?
|
||||
if ('0' <= ch && ch <= '9')
|
||||
{
|
||||
periodAllowed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '.')
|
||||
{
|
||||
if (!periodAllowed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
periodAllowed = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return periodAllowed;
|
||||
}
|
||||
|
||||
private static boolean isValidIdentifier(
|
||||
String identifier)
|
||||
{
|
||||
if (identifier.length() < 3 || identifier.charAt(1) != '.')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char first = identifier.charAt(0);
|
||||
if (first < '0' || first > '2')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValidBranchID(identifier, 2);
|
||||
}
|
||||
|
||||
private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
|
||||
|
||||
static ASN1ObjectIdentifier fromOctetString(byte[] enc)
|
||||
{
|
||||
if (enc.length < 3)
|
||||
{
|
||||
return new ASN1ObjectIdentifier(enc);
|
||||
}
|
||||
|
||||
int idx1 = enc[enc.length - 2] & 0xff;
|
||||
// in this case top bit is always zero
|
||||
int idx2 = enc[enc.length - 1] & 0x7f;
|
||||
|
||||
ASN1ObjectIdentifier possibleMatch;
|
||||
|
||||
synchronized (cache)
|
||||
{
|
||||
ASN1ObjectIdentifier[] first = cache[idx1];
|
||||
if (first == null)
|
||||
{
|
||||
first = cache[idx1] = new ASN1ObjectIdentifier[128];
|
||||
}
|
||||
|
||||
possibleMatch = first[idx2];
|
||||
if (possibleMatch == null)
|
||||
{
|
||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
||||
}
|
||||
|
||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
||||
{
|
||||
return possibleMatch;
|
||||
}
|
||||
|
||||
idx1 = (idx1 + 1) & 0xff;
|
||||
first = cache[idx1];
|
||||
if (first == null)
|
||||
{
|
||||
first = cache[idx1] = new ASN1ObjectIdentifier[128];
|
||||
}
|
||||
|
||||
possibleMatch = first[idx2];
|
||||
if (possibleMatch == null)
|
||||
{
|
||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
||||
}
|
||||
|
||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
||||
{
|
||||
return possibleMatch;
|
||||
}
|
||||
|
||||
idx2 = (idx2 + 1) & 0x7f;
|
||||
possibleMatch = first[idx2];
|
||||
if (possibleMatch == null)
|
||||
{
|
||||
return first[idx2] = new ASN1ObjectIdentifier(enc);
|
||||
}
|
||||
}
|
||||
|
||||
if (Arrays.areEqual(enc, possibleMatch.getBody()))
|
||||
{
|
||||
return possibleMatch;
|
||||
}
|
||||
|
||||
return new ASN1ObjectIdentifier(enc);
|
||||
super(oid, branch);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue