001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Alexander Y. Kleymenov
020: * @version $Revision$
021: */package org.apache.harmony.security.provider.cert;
022:
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.math.BigInteger;
026: import java.security.InvalidKeyException;
027: import java.security.NoSuchAlgorithmException;
028: import java.security.NoSuchProviderException;
029: import java.security.Principal;
030: import java.security.PublicKey;
031: import java.security.Signature;
032: import java.security.SignatureException;
033: import java.security.cert.CertificateEncodingException;
034: import java.security.cert.CertificateException;
035: import java.security.cert.CertificateExpiredException;
036: import java.security.cert.CertificateNotYetValidException;
037: import java.security.cert.CertificateParsingException;
038: import java.security.cert.X509Certificate;
039: import java.util.Collection;
040: import java.util.Date;
041: import java.util.List;
042: import java.util.Set;
043:
044: import javax.security.auth.x500.X500Principal;
045:
046: import org.apache.harmony.security.internal.nls.Messages;
047: import org.apache.harmony.security.utils.AlgNameMapper;
048: import org.apache.harmony.security.x509.Certificate;
049: import org.apache.harmony.security.x509.Extension;
050: import org.apache.harmony.security.x509.Extensions;
051: import org.apache.harmony.security.x509.TBSCertificate;
052:
053: /**
054: * This class is an implementation of X509Certificate. It wraps
055: * the instance of org.apache.harmony.security.x509.Certificate
056: * built on the base of provided ASN.1 DER encoded form of
057: * Certificate structure (as specified in RFC 3280
058: * http://www.ietf.org/rfc/rfc3280.txt).
059: * @see org.apache.harmony.security.x509.Certificate
060: * @see java.security.cert.X509Certificate
061: */
062: public class X509CertImpl extends X509Certificate {
063:
064: /**
065: * @serial
066: */
067: private static final long serialVersionUID = 2972248729446736154L;
068:
069: // the core object to be wrapped in X509Certificate
070: private final Certificate certificate;
071:
072: // to speed up access to the info, the following fields
073: // cache values retrieved from the certificate object
074: private final TBSCertificate tbsCert;
075: private final Extensions extensions;
076: private long notBefore = -1;
077: private long notAfter;
078: private BigInteger serialNumber;
079: private X500Principal issuer;
080: private X500Principal subject;
081: private byte[] tbsCertificate;
082: private byte[] signature;
083: private String sigAlgName;
084: private String sigAlgOID;
085: private byte[] sigAlgParams;
086: // indicates whether the signature algorithm parameters are null
087: private boolean nullSigAlgParams;
088: private PublicKey publicKey;
089:
090: // encoding of the certificate
091: private byte[] encoding;
092:
093: //
094: // ---------------------- Constructors -------------------------------
095: //
096:
097: /**
098: * Constructs the instance on the base of ASN.1 encoded
099: * form of X.509 certificate provided via stream parameter.
100: * @param in input stream containing ASN.1 encoded form of certificate.
101: * @throws CertificateException if some decoding problems occur.
102: */
103: public X509CertImpl(InputStream in) throws CertificateException {
104: try {
105: // decode the Certificate object
106: this .certificate = (Certificate) Certificate.ASN1
107: .decode(in);
108: // cache the values of TBSCertificate and Extensions
109: this .tbsCert = certificate.getTbsCertificate();
110: this .extensions = tbsCert.getExtensions();
111: } catch (IOException e) {
112: throw new CertificateException(e);
113: }
114: }
115:
116: /**
117: * Constructs the instance on the base of existing Certificate object to
118: * be wrapped.
119: */
120: public X509CertImpl(Certificate certificate) {
121: this .certificate = certificate;
122: // cache the values of TBSCertificate and Extensions
123: this .tbsCert = certificate.getTbsCertificate();
124: this .extensions = tbsCert.getExtensions();
125: }
126:
127: /**
128: * Constructs the instance on the base of ASN.1 encoded
129: * form of X.509 certificate provided via array of bytes.
130: * @param encoding byte array containing ASN.1 encoded form of certificate.
131: * @throws IOException if some decoding problems occur.
132: */
133: public X509CertImpl(byte[] encoding) throws IOException {
134: this ((Certificate) Certificate.ASN1.decode(encoding));
135: }
136:
137: //
138: // ----------------- Public methods implementations ------------------
139: //
140:
141: /**
142: * @see java.security.cert.X509Certificate#checkValidity()
143: * method documentation for more information.
144: */
145: public void checkValidity() throws CertificateExpiredException,
146: CertificateNotYetValidException {
147: if (notBefore == -1) {
148: // retrieve and cache the value of validity period
149: notBefore = tbsCert.getValidity().getNotBefore().getTime();
150: notAfter = tbsCert.getValidity().getNotAfter().getTime();
151: }
152: long time = System.currentTimeMillis();
153: if (time < notBefore) {
154: throw new CertificateNotYetValidException();
155: }
156: if (time > notAfter) {
157: throw new CertificateExpiredException();
158: }
159: }
160:
161: /**
162: * @see java.security.cert.X509Certificate#checkValidity(Date)
163: * method documentation for more information.
164: */
165: public void checkValidity(Date date)
166: throws CertificateExpiredException,
167: CertificateNotYetValidException {
168: if (notBefore == -1) {
169: // retrieve and cache the value of validity period
170: notBefore = tbsCert.getValidity().getNotBefore().getTime();
171: notAfter = tbsCert.getValidity().getNotAfter().getTime();
172: }
173: long time = date.getTime();
174: if (time < notBefore) {
175: throw new CertificateNotYetValidException();
176: }
177: if (time > notAfter) {
178: throw new CertificateExpiredException();
179: }
180: }
181:
182: /**
183: * @see java.security.cert.X509Certificate#getVersion()
184: * method documentation for more information.
185: */
186: public int getVersion() {
187: return tbsCert.getVersion() + 1;
188: }
189:
190: /**
191: * @see java.security.cert.X509Certificate#getSerialNumber()
192: * method documentation for more information.
193: */
194: public BigInteger getSerialNumber() {
195: if (serialNumber == null) {
196: serialNumber = tbsCert.getSerialNumber();
197: }
198: return serialNumber;
199: }
200:
201: /**
202: * @see java.security.cert.X509Certificate#getIssuerDN()
203: * method documentation for more information.
204: */
205: public Principal getIssuerDN() {
206: if (issuer == null) {
207: // retrieve the issuer's principal
208: issuer = tbsCert.getIssuer().getX500Principal();
209: }
210: return issuer;
211: }
212:
213: /**
214: * @see java.security.cert.X509Certificate#getIssuerX500Principal()
215: * method documentation for more information.
216: */
217: public X500Principal getIssuerX500Principal() {
218: if (issuer == null) {
219: // retrieve the issuer's principal
220: issuer = tbsCert.getIssuer().getX500Principal();
221: }
222: return issuer;
223: }
224:
225: /**
226: * @see java.security.cert.X509Certificate#getSubjectDN()
227: * method documentation for more information.
228: */
229: public Principal getSubjectDN() {
230: if (subject == null) {
231: // retrieve the subject's principal
232: subject = tbsCert.getSubject().getX500Principal();
233: }
234: return subject;
235: }
236:
237: /**
238: * @see java.security.cert.X509Certificate#getSubjectX500Principal()
239: * method documentation for more information.
240: */
241: public X500Principal getSubjectX500Principal() {
242: if (subject == null) {
243: // retrieve the subject's principal
244: subject = tbsCert.getSubject().getX500Principal();
245: }
246: return subject;
247: }
248:
249: /**
250: * @see java.security.cert.X509Certificate#getNotBefore()
251: * method documentation for more information.
252: */
253: public Date getNotBefore() {
254: if (notBefore == -1) {
255: // the value was not retrieved from the certificate, do it:
256: notBefore = tbsCert.getValidity().getNotBefore().getTime();
257: notAfter = tbsCert.getValidity().getNotAfter().getTime();
258: }
259: return new Date(notBefore);
260: }
261:
262: /**
263: * @see java.security.cert.X509Certificate#getNotAfter()
264: * method documentation for more information.
265: */
266: public Date getNotAfter() {
267: if (notBefore == -1) {
268: // the value was not retrieved from the certificate, do it:
269: notBefore = tbsCert.getValidity().getNotBefore().getTime();
270: notAfter = tbsCert.getValidity().getNotAfter().getTime();
271: }
272: return new Date(notAfter);
273: }
274:
275: /**
276: * @see java.security.cert.X509Certificate#getTBSCertificate()
277: * method documentation for more information.
278: */
279: public byte[] getTBSCertificate()
280: throws CertificateEncodingException {
281: if (tbsCertificate == null) {
282: // retrieve the encoded form of the TBSCertificate structure
283: tbsCertificate = tbsCert.getEncoded();
284: }
285: byte[] result = new byte[tbsCertificate.length];
286: System.arraycopy(tbsCertificate, 0, result, 0,
287: tbsCertificate.length);
288: return result;
289: }
290:
291: /**
292: * @see java.security.cert.X509Certificate#getSignature()
293: * method documentation for more information.
294: */
295: public byte[] getSignature() {
296: if (signature == null) {
297: // retrieve the value of the signature
298: signature = certificate.getSignatureValue();
299: }
300: byte[] result = new byte[signature.length];
301: System.arraycopy(signature, 0, result, 0, signature.length);
302: return result;
303: }
304:
305: /**
306: * @see java.security.cert.X509Certificate#getSigAlgName()
307: * method documentation for more information.
308: */
309: public String getSigAlgName() {
310: if (sigAlgOID == null) {
311: // if info was not retrieved (and cached), do it:
312: sigAlgOID = tbsCert.getSignature().getAlgorithm();
313: // retrieve the name of the signing algorithm
314: sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
315: if (sigAlgName == null) {
316: // if could not be found, use OID as a name
317: sigAlgName = sigAlgOID;
318: }
319: }
320: return sigAlgName;
321: }
322:
323: /**
324: * @see java.security.cert.X509Certificate#getSigAlgOID()
325: * method documentation for more information.
326: */
327: public String getSigAlgOID() {
328: if (sigAlgOID == null) {
329: // if info was not retrieved (and cached), do it:
330: sigAlgOID = tbsCert.getSignature().getAlgorithm();
331: // retrieve the name of the signing algorithm
332: sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
333: if (sigAlgName == null) {
334: // if could not be found, use OID as a name
335: sigAlgName = sigAlgOID;
336: }
337: }
338: return sigAlgOID;
339: }
340:
341: /**
342: * @see java.security.cert.X509Certificate#getSigAlgParams()
343: * method documentation for more information.
344: */
345: public byte[] getSigAlgParams() {
346: if (nullSigAlgParams) {
347: return null;
348: }
349: if (sigAlgParams == null) {
350: sigAlgParams = tbsCert.getSignature().getParameters();
351: if (sigAlgParams == null) {
352: nullSigAlgParams = true;
353: return null;
354: }
355: }
356: return sigAlgParams;
357: }
358:
359: /**
360: * @see java.security.cert.X509Certificate#getIssuerUniqueID()
361: * method documentation for more information.
362: */
363: public boolean[] getIssuerUniqueID() {
364: return tbsCert.getIssuerUniqueID();
365: }
366:
367: /**
368: * @see java.security.cert.X509Certificate#getSubjectUniqueID()
369: * method documentation for more information.
370: */
371: public boolean[] getSubjectUniqueID() {
372: return tbsCert.getSubjectUniqueID();
373: }
374:
375: /**
376: * @see java.security.cert.X509Certificate#getKeyUsage()
377: * method documentation for more information.
378: */
379: public boolean[] getKeyUsage() {
380: if (extensions == null) {
381: return null;
382: }
383: return extensions.valueOfKeyUsage();
384: }
385:
386: /**
387: * @see java.security.cert.X509Certificate#getExtendedKeyUsage()
388: * method documentation for more information.
389: */
390: public List/*<String>*/getExtendedKeyUsage()
391: throws CertificateParsingException {
392: if (extensions == null) {
393: return null;
394: }
395: try {
396: return extensions.valueOfExtendedKeyUsage();
397: } catch (IOException e) {
398: throw new CertificateParsingException(e);
399: }
400: }
401:
402: /**
403: * @see java.security.cert.X509Certificate#getBasicConstraints()
404: * method documentation for more information.
405: */
406: public int getBasicConstraints() {
407: if (extensions == null) {
408: return Integer.MAX_VALUE;
409: }
410: return extensions.valueOfBasicConstrains();
411: }
412:
413: /**
414: * @see java.security.cert.X509Certificate#getSubjectAlternativeNames()
415: * method documentation for more information.
416: */
417: public Collection/*<List<?>>*/getSubjectAlternativeNames()
418: throws CertificateParsingException {
419: if (extensions == null) {
420: return null;
421: }
422: try {
423: // Retrieve the extension value from the cached extensions object
424: // This extension is not checked for correctness during
425: // certificate generation, so now it can throw exception
426: return extensions.valueOfSubjectAlternativeName();
427: } catch (IOException e) {
428: throw new CertificateParsingException(e);
429: }
430: }
431:
432: /**
433: * @see java.security.cert.X509Certificate#getIssuerAlternativeNames()
434: * method documentation for more information.
435: */
436: public Collection/*FIXME <List<?>>*/getIssuerAlternativeNames()
437: throws CertificateParsingException {
438: if (extensions == null) {
439: return null;
440: }
441: try {
442: // Retrieve the extension value from the cached extensions object
443: // This extension is not checked for correctness during
444: // certificate generation, so now it can throw exception
445: return extensions.valueOfIssuerAlternativeName();
446: } catch (IOException e) {
447: throw new CertificateParsingException(e);
448: }
449: }
450:
451: //
452: // ----- java.security.cert.Certificate methods implementations ------
453: //
454:
455: /**
456: * @see java.security.cert.Certificate#getEncoded()
457: * method documentation for more information.
458: */
459: public byte[] getEncoded() throws CertificateEncodingException {
460: if (encoding == null) {
461: encoding = certificate.getEncoded();
462: }
463: byte[] result = new byte[encoding.length];
464: System.arraycopy(encoding, 0, result, 0, encoding.length);
465: return result;
466: }
467:
468: /**
469: * @see java.security.cert.Certificate#getPublicKey()
470: * method documentation for more information.
471: */
472: public PublicKey getPublicKey() {
473: if (publicKey == null) {
474: // retrieve the public key from SubjectPublicKeyInfo
475: // substructure of X.509 certificate
476: publicKey = tbsCert.getSubjectPublicKeyInfo()
477: .getPublicKey();
478: }
479: return publicKey;
480: }
481:
482: /**
483: * @see java.security.cert.Certificate#toString()
484: * method documentation for more information.
485: */
486: public String toString() {
487: return certificate.toString();
488: }
489:
490: /**
491: * Verifies the signature of the certificate.
492: * @see java.security.cert.Certificate#verify(PublicKey)
493: * method documentation for more information.
494: */
495: public void verify(PublicKey key) throws CertificateException,
496: NoSuchAlgorithmException, InvalidKeyException,
497: NoSuchProviderException, SignatureException {
498: Signature signature = Signature.getInstance(getSigAlgName());
499: signature.initVerify(key);
500: // retrieve the encoding of the TBSCertificate structure
501: if (tbsCertificate == null) {
502: tbsCertificate = tbsCert.getEncoded();
503: }
504: // compute and verify the signature
505: signature.update(tbsCertificate, 0, tbsCertificate.length);
506: if (!signature.verify(certificate.getSignatureValue())) {
507: throw new SignatureException(Messages
508: .getString("security.15C")); //$NON-NLS-1$
509: }
510: }
511:
512: /**
513: * Verifies the signature of the certificate.
514: * @see java.security.cert.Certificate#verify(PublicKey,String)
515: * method documentation for more information.
516: */
517: public void verify(PublicKey key, String sigProvider)
518: throws CertificateException, NoSuchAlgorithmException,
519: InvalidKeyException, NoSuchProviderException,
520: SignatureException {
521: Signature signature = Signature.getInstance(getSigAlgName(),
522: sigProvider);
523: signature.initVerify(key);
524: // retrieve the encoding of the TBSCertificate structure
525: if (tbsCertificate == null) {
526: tbsCertificate = tbsCert.getEncoded();
527: }
528: // compute and verify the signature
529: signature.update(tbsCertificate, 0, tbsCertificate.length);
530: if (!signature.verify(certificate.getSignatureValue())) {
531: throw new SignatureException(Messages
532: .getString("security.15C")); //$NON-NLS-1$
533: }
534: }
535:
536: //
537: // ----- java.security.cert.X509Extension methods implementations ----
538: //
539:
540: /**
541: * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
542: * method documentation for more information.
543: */
544: public Set getNonCriticalExtensionOIDs() {
545: if (extensions == null) {
546: return null;
547: }
548: // retrieve the info from the cached extensions object
549: return extensions.getNonCriticalExtensions();
550: }
551:
552: /**
553: * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
554: * method documentation for more information.
555: */
556: public Set getCriticalExtensionOIDs() {
557: if (extensions == null) {
558: return null;
559: }
560: // retrieve the info from the cached extensions object
561: return extensions.getCriticalExtensions();
562: }
563:
564: /**
565: * @see java.security.cert.X509Extension#getExtensionValue(String)
566: * method documentation for more information.
567: */
568: public byte[] getExtensionValue(String oid) {
569: if (extensions == null) {
570: return null;
571: }
572: // retrieve the info from the cached extensions object
573: Extension ext = extensions.getExtensionByOID(oid);
574: return (ext == null) ? null : ext.getRawExtnValue();
575: }
576:
577: /**
578: * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
579: * method documentation for more information.
580: */
581: public boolean hasUnsupportedCriticalExtension() {
582: if (extensions == null) {
583: return false;
584: }
585: // retrieve the info from the cached extensions object
586: return extensions.hasUnsupportedCritical();
587: }
588:
589: }
|