001: package org.bouncycastle.tsp;
002:
003: import org.bouncycastle.asn1.ASN1InputStream;
004: import org.bouncycastle.asn1.DERObjectIdentifier;
005: import org.bouncycastle.asn1.cmp.PKIFailureInfo;
006: import org.bouncycastle.asn1.tsp.TimeStampReq;
007: import org.bouncycastle.asn1.x509.X509Extensions;
008:
009: import java.io.ByteArrayInputStream;
010: import java.io.IOException;
011: import java.io.InputStream;
012: import java.math.BigInteger;
013: import java.security.NoSuchProviderException;
014: import java.security.cert.X509Extension;
015: import java.util.Enumeration;
016: import java.util.HashSet;
017: import java.util.Set;
018:
019: /**
020: * Base class for an RFC 3161 Time Stamp Request.
021: */
022: public class TimeStampRequest implements X509Extension {
023: TimeStampReq req;
024:
025: public TimeStampRequest(TimeStampReq req) {
026: this .req = req;
027: }
028:
029: /**
030: * Create a TimeStampRequest from the past in byte array.
031: *
032: * @param req byte array containing the request.
033: * @throws IOException if the request is malformed.
034: */
035: public TimeStampRequest(byte[] req) throws IOException {
036: this (new ByteArrayInputStream(req));
037: }
038:
039: /**
040: * Create a TimeStampRequest from the past in input stream.
041: *
042: * @param in input stream containing the request.
043: * @throws IOException if the request is malformed.
044: */
045: public TimeStampRequest(InputStream in) throws IOException {
046: try {
047: this .req = TimeStampReq.getInstance(new ASN1InputStream(in)
048: .readObject());
049: } catch (ClassCastException e) {
050: throw new IOException("malformed request: " + e);
051: } catch (IllegalArgumentException e) {
052: throw new IOException("malformed request: " + e);
053: }
054: }
055:
056: public int getVersion() {
057: return req.getVersion().getValue().intValue();
058: }
059:
060: public String getMessageImprintAlgOID() {
061: return req.getMessageImprint().getHashAlgorithm().getObjectId()
062: .getId();
063: }
064:
065: public byte[] getMessageImprintDigest() {
066: return req.getMessageImprint().getHashedMessage();
067: }
068:
069: public String getReqPolicy() {
070: if (req.getReqPolicy() != null) {
071: return req.getReqPolicy().getId();
072: } else {
073: return null;
074: }
075: }
076:
077: public BigInteger getNonce() {
078: if (req.getNonce() != null) {
079: return req.getNonce().getValue();
080: } else {
081: return null;
082: }
083: }
084:
085: public boolean getCertReq() {
086: if (req.getCertReq() != null) {
087: return req.getCertReq().isTrue();
088: } else {
089: return false;
090: }
091: }
092:
093: /**
094: * Validate the timestamp request, checking the digest to see if it is of an
095: * accepted type and whether it is of the correct length for the algorithm specified.
096: *
097: * @param algorithms a set of String OIDS giving accepted algorithms.
098: * @param policies if non-null a set of policies we are willing to sign under.
099: * @param extensions if non-null a set of extensions we are willing to accept.
100: * @param provider the provider to confirm the digest size against.
101: * @throws TSPException if the request is invalid, or processing fails.
102: */
103: public void validate(Set algorithms, Set policies, Set extensions,
104: String provider) throws TSPException,
105: NoSuchProviderException {
106: if (!algorithms.contains(this .getMessageImprintAlgOID())) {
107: throw new TSPValidationException(
108: "request contains unknown algorithm.",
109: PKIFailureInfo.badAlg);
110: }
111:
112: if (policies != null && this .getReqPolicy() != null
113: && !policies.contains(this .getReqPolicy())) {
114: throw new TSPValidationException(
115: "request contains unknown policy.",
116: PKIFailureInfo.unacceptedPolicy);
117: }
118:
119: if (this .getExtensions() != null && extensions != null) {
120: Enumeration en = this .getExtensions().oids();
121: while (en.hasMoreElements()) {
122: String oid = ((DERObjectIdentifier) en.nextElement())
123: .getId();
124: if (!extensions.contains(oid)) {
125: throw new TSPValidationException(
126: "request contains unknown extension.",
127: PKIFailureInfo.unacceptedExtension);
128: }
129: }
130: }
131:
132: int digestLength = TSPUtil.getDigestLength(this
133: .getMessageImprintAlgOID(), provider);
134:
135: if (digestLength != this .getMessageImprintDigest().length) {
136: throw new TSPValidationException(
137: "imprint digest the wrong length.",
138: PKIFailureInfo.badDataFormat);
139: }
140: }
141:
142: /**
143: * return the ASN.1 encoded representation of this object.
144: */
145: public byte[] getEncoded() throws IOException {
146: return req.getEncoded();
147: }
148:
149: X509Extensions getExtensions() {
150: return req.getExtensions();
151: }
152:
153: /* (non-Javadoc)
154: * @see java.security.cert.X509Extension#getExtensionValue(java.lang.String)
155: */
156: public byte[] getExtensionValue(String oid) {
157: X509Extensions exts = req.getExtensions();
158:
159: if (exts != null) {
160: org.bouncycastle.asn1.x509.X509Extension ext = exts
161: .getExtension(new DERObjectIdentifier(oid));
162:
163: if (ext != null) {
164: try {
165: return ext.getValue().getEncoded();
166: } catch (Exception e) {
167: throw new RuntimeException("error encoding "
168: + e.toString());
169: }
170: }
171: }
172:
173: return null;
174: }
175:
176: private Set getExtensionOIDS(boolean critical) {
177: Set set = new HashSet();
178: X509Extensions extensions = req.getExtensions();
179:
180: if (extensions != null) {
181: Enumeration e = extensions.oids();
182:
183: while (e.hasMoreElements()) {
184: DERObjectIdentifier oid = (DERObjectIdentifier) e
185: .nextElement();
186: org.bouncycastle.asn1.x509.X509Extension ext = extensions
187: .getExtension(oid);
188:
189: if (ext.isCritical() == critical) {
190: set.add(oid.getId());
191: }
192: }
193:
194: return set;
195: }
196:
197: return null;
198: }
199:
200: public Set getNonCriticalExtensionOIDs() {
201: return getExtensionOIDS(false);
202: }
203:
204: public Set getCriticalExtensionOIDs() {
205: return getExtensionOIDS(true);
206: }
207:
208: public boolean hasUnsupportedCriticalExtension() {
209: return false;
210: }
211: }
|