001: package org.bouncycastle.x509;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1Sequence;
005: import org.bouncycastle.asn1.DERInteger;
006: import org.bouncycastle.asn1.DERSequence;
007: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
008: import org.bouncycastle.asn1.x509.GeneralName;
009: import org.bouncycastle.asn1.x509.GeneralNames;
010: import org.bouncycastle.asn1.x509.Holder;
011: import org.bouncycastle.asn1.x509.IssuerSerial;
012: import org.bouncycastle.asn1.x509.ObjectDigestInfo;
013: import org.bouncycastle.jce.PrincipalUtil;
014: import org.bouncycastle.jce.X509Principal;
015: import org.bouncycastle.util.Arrays;
016: import org.bouncycastle.util.Selector;
017:
018: import javax.security.auth.x500.X500Principal;
019: import java.io.IOException;
020: import java.math.BigInteger;
021: import java.security.MessageDigest;
022: import java.security.Principal;
023: import java.security.cert.CertSelector;
024: import java.security.cert.Certificate;
025: import java.security.cert.CertificateEncodingException;
026: import java.security.cert.CertificateParsingException;
027: import java.security.cert.X509Certificate;
028: import java.util.ArrayList;
029: import java.util.List;
030:
031: /**
032: * The Holder object.
033: *
034: * <pre>
035: * Holder ::= SEQUENCE {
036: * baseCertificateID [0] IssuerSerial OPTIONAL,
037: * -- the issuer and serial number of
038: * -- the holder's Public Key Certificate
039: * entityName [1] GeneralNames OPTIONAL,
040: * -- the name of the claimant or role
041: * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
042: * -- used to directly authenticate the holder,
043: * -- for example, an executable
044: * }
045: * </pre>
046: *
047: */
048: public class AttributeCertificateHolder implements CertSelector,
049: Selector {
050: final Holder holder;
051:
052: AttributeCertificateHolder(ASN1Sequence seq) {
053: holder = Holder.getInstance(seq);
054: }
055:
056: public AttributeCertificateHolder(X509Principal issuerName,
057: BigInteger serialNumber) {
058: holder = new org.bouncycastle.asn1.x509.Holder(
059: new IssuerSerial(new GeneralNames(new DERSequence(
060: new GeneralName(issuerName))), new DERInteger(
061: serialNumber)));
062: }
063:
064: public AttributeCertificateHolder(X500Principal issuerName,
065: BigInteger serialNumber) {
066: this (X509Util.convertPrincipal(issuerName), serialNumber);
067: }
068:
069: public AttributeCertificateHolder(X509Certificate cert)
070: throws CertificateParsingException {
071: X509Principal name;
072:
073: try {
074: name = PrincipalUtil.getIssuerX509Principal(cert);
075: } catch (Exception e) {
076: throw new CertificateParsingException(e.getMessage());
077: }
078:
079: holder = new Holder(new IssuerSerial(
080: generateGeneralNames(name), new DERInteger(cert
081: .getSerialNumber())));
082: }
083:
084: public AttributeCertificateHolder(X509Principal principal) {
085: holder = new Holder(generateGeneralNames(principal));
086: }
087:
088: public AttributeCertificateHolder(X500Principal principal) {
089: this (X509Util.convertPrincipal(principal));
090: }
091:
092: /**
093: * Constructs a holder for v2 attribute certificates with a hash value for
094: * some type of object.
095: * <p>
096: * <code>digestedObjectType</code> can be one of the following:
097: * <ul>
098: * <li>0 - publicKey - A hash of the public key of the holder must be
099: * passed.
100: * <li>1 - publicKeyCert - A hash of the public key certificate of the
101: * holder must be passed.
102: * <li>2 - otherObjectDigest - A hash of some other object type must be
103: * passed. <code>otherObjectTypeID</code> must not be empty.
104: * </ul>
105: * <p>
106: * This cannot be used if a v1 attribute certificate is used.
107: *
108: * @param digestedObjectType The digest object type.
109: * @param digestAlgorithm The algorithm identifier for the hash.
110: * @param otherObjectTypeID The object type ID if
111: * <code>digestedObjectType</code> is
112: * <code>otherObjectDigest</code>.
113: * @param objectDigest The hash value.
114: */
115: public AttributeCertificateHolder(int digestedObjectType,
116: String digestAlgorithm, String otherObjectTypeID,
117: byte[] objectDigest) {
118: holder = new Holder(new ObjectDigestInfo(digestedObjectType,
119: otherObjectTypeID, new AlgorithmIdentifier(
120: digestAlgorithm), Arrays.clone(objectDigest)));
121: }
122:
123: /**
124: * Returns the digest object type if an object digest info is used.
125: * <p>
126: * <ul>
127: * <li>0 - publicKey - A hash of the public key of the holder must be
128: * passed.
129: * <li>1 - publicKeyCert - A hash of the public key certificate of the
130: * holder must be passed.
131: * <li>2 - otherObjectDigest - A hash of some other object type must be
132: * passed. <code>otherObjectTypeID</code> must not be empty.
133: * </ul>
134: *
135: * @return The digest object type or -1 if no object digest info is set.
136: */
137: public int getDigestedObjectType() {
138: if (holder.getObjectDigestInfo() != null) {
139: return holder.getObjectDigestInfo().getDigestedObjectType()
140: .getValue().intValue();
141: }
142: return -1;
143: }
144:
145: /**
146: * Returns the other object type ID if an object digest info is used.
147: *
148: * @return The other object type ID or <code>null</code> if no object
149: * digest info is set.
150: */
151: public String getDigestAlgorithm() {
152: if (holder.getObjectDigestInfo() != null) {
153: holder.getObjectDigestInfo().getDigestAlgorithm()
154: .getObjectId().getId();
155: }
156: return null;
157: }
158:
159: /**
160: * Returns the hash if an object digest info is used.
161: *
162: * @return The hash or <code>null</code> if no object digest info is set.
163: */
164: public byte[] getObjectDigest() {
165: if (holder.getObjectDigestInfo() != null) {
166: holder.getObjectDigestInfo().getObjectDigest().getBytes();
167: }
168: return null;
169: }
170:
171: /**
172: * Returns the digest algorithm ID if an object digest info is used.
173: *
174: * @return The digest algorithm ID or <code>null</code> if no object
175: * digest info is set.
176: */
177: public String getOtherObjectTypeID() {
178: if (holder.getObjectDigestInfo() != null) {
179: holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
180: }
181: return null;
182: }
183:
184: private GeneralNames generateGeneralNames(X509Principal principal) {
185: return new GeneralNames(new DERSequence(new GeneralName(
186: principal)));
187: }
188:
189: private boolean matchesDN(X509Principal subject,
190: GeneralNames targets) {
191: GeneralName[] names = targets.getNames();
192:
193: for (int i = 0; i != names.length; i++) {
194: GeneralName gn = names[i];
195:
196: if (gn.getTagNo() == GeneralName.directoryName) {
197: try {
198: if (new X509Principal(
199: ((ASN1Encodable) gn.getName()).getEncoded())
200: .equals(subject)) {
201: return true;
202: }
203: } catch (IOException e) {
204: }
205: }
206: }
207:
208: return false;
209: }
210:
211: private Object[] getNames(GeneralName[] names) {
212: List l = new ArrayList(names.length);
213:
214: for (int i = 0; i != names.length; i++) {
215: if (names[i].getTagNo() == GeneralName.directoryName) {
216: try {
217: l.add(new X500Principal(((ASN1Encodable) names[i]
218: .getName()).getEncoded()));
219: } catch (IOException e) {
220: throw new RuntimeException(
221: "badly formed Name object");
222: }
223: }
224: }
225:
226: return l.toArray(new Object[l.size()]);
227: }
228:
229: private Principal[] getPrincipals(GeneralNames names) {
230: Object[] p = this .getNames(names.getNames());
231: List l = new ArrayList();
232:
233: for (int i = 0; i != p.length; i++) {
234: if (p[i] instanceof Principal) {
235: l.add(p[i]);
236: }
237: }
238:
239: return (Principal[]) l.toArray(new Principal[l.size()]);
240: }
241:
242: /**
243: * Return any principal objects inside the attribute certificate holder
244: * entity names field.
245: *
246: * @return an array of Principal objects (usually X500Principal), null if no
247: * entity names field is set.
248: */
249: public Principal[] getEntityNames() {
250: if (holder.getEntityName() != null) {
251: return getPrincipals(holder.getEntityName());
252: }
253:
254: return null;
255: }
256:
257: /**
258: * Return the principals associated with the issuer attached to this holder
259: *
260: * @return an array of principals, null if no BaseCertificateID is set.
261: */
262: public Principal[] getIssuer() {
263: if (holder.getBaseCertificateID() != null) {
264: return getPrincipals(holder.getBaseCertificateID()
265: .getIssuer());
266: }
267:
268: return null;
269: }
270:
271: /**
272: * Return the serial number associated with the issuer attached to this
273: * holder.
274: *
275: * @return the certificate serial number, null if no BaseCertificateID is
276: * set.
277: */
278: public BigInteger getSerialNumber() {
279: if (holder.getBaseCertificateID() != null) {
280: return holder.getBaseCertificateID().getSerial().getValue();
281: }
282:
283: return null;
284: }
285:
286: public Object clone() {
287: return new AttributeCertificateHolder((ASN1Sequence) holder
288: .toASN1Object());
289: }
290:
291: public boolean match(Certificate cert) {
292: if (!(cert instanceof X509Certificate)) {
293: return false;
294: }
295:
296: X509Certificate x509Cert = (X509Certificate) cert;
297:
298: try {
299: if (holder.getBaseCertificateID() != null) {
300: return holder.getBaseCertificateID().getSerial()
301: .getValue().equals(x509Cert.getSerialNumber())
302: && matchesDN(PrincipalUtil
303: .getIssuerX509Principal(x509Cert),
304: holder.getBaseCertificateID()
305: .getIssuer());
306: }
307:
308: if (holder.getEntityName() != null) {
309: if (matchesDN(PrincipalUtil
310: .getSubjectX509Principal(x509Cert), holder
311: .getEntityName())) {
312: return true;
313: }
314: }
315: if (holder.getObjectDigestInfo() != null) {
316: MessageDigest md = null;
317: try {
318: md = MessageDigest.getInstance(
319: getDigestAlgorithm(), "BC");
320:
321: } catch (Exception e) {
322: return false;
323: }
324: switch (getDigestedObjectType()) {
325: case ObjectDigestInfo.publicKey:
326: // TODO: DSA Dss-parms
327: md.update(cert.getPublicKey().getEncoded());
328: break;
329: case ObjectDigestInfo.publicKeyCert:
330: md.update(cert.getEncoded());
331: break;
332: }
333: if (!Arrays.areEqual(md.digest(), getObjectDigest())) {
334: return false;
335: }
336: }
337: } catch (CertificateEncodingException e) {
338: return false;
339: }
340:
341: return false;
342: }
343:
344: public boolean equals(Object obj) {
345: if (obj == this ) {
346: return true;
347: }
348:
349: if (!(obj instanceof AttributeCertificateHolder)) {
350: return false;
351: }
352:
353: AttributeCertificateHolder other = (AttributeCertificateHolder) obj;
354:
355: return this .holder.equals(other.holder);
356: }
357:
358: public int hashCode() {
359: return this .holder.hashCode();
360: }
361:
362: public boolean match(Object obj) {
363: if (!(obj instanceof X509Certificate)) {
364: return false;
365: }
366:
367: return match((Certificate) obj);
368: }
369: }
|