001: /*
002: * @(#)X509Certificate.java 1.34 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.security.cert;
029:
030: import java.math.BigInteger;
031: import java.security.Principal;
032: import java.security.PublicKey;
033: import java.util.Collection;
034: import java.util.Date;
035: import java.util.List;
036: import javax.security.auth.x500.X500Principal;
037:
038: import sun.security.x509.X509CertImpl;
039:
040: /**
041: * <p>
042: * Abstract class for X.509 certificates. This provides a standard
043: * way to access all the attributes of an X.509 certificate.
044: * <p>
045: * In June of 1996, the basic X.509 v3 format was completed by
046: * ISO/IEC and ANSI X9, which is described below in ASN.1:
047: * <pre>
048: * Certificate ::= SEQUENCE {
049: * tbsCertificate TBSCertificate,
050: * signatureAlgorithm AlgorithmIdentifier,
051: * signature BIT STRING }
052: * </pre>
053: * <p>
054: * These certificates are widely used to support authentication and
055: * other functionality in Internet security systems. Common applications
056: * include Privacy Enhanced Mail (PEM), Transport Layer Security (SSL),
057: * code signing for trusted software distribution, and Secure Electronic
058: * Transactions (SET).
059: * <p>
060: * These certificates are managed and vouched for by <em>Certificate
061: * Authorities</em> (CAs). CAs are services which create certificates by
062: * placing data in the X.509 standard format and then digitally signing
063: * that data. CAs act as trusted third parties, making introductions
064: * between principals who have no direct knowledge of each other.
065: * CA certificates are either signed by themselves, or by some other
066: * CA such as a "root" CA.
067: * <p>
068: * More information can be found in RFC 2459,
069: * "Internet X.509 Public Key Infrastructure Certificate and CRL
070: * Profile" at <A HREF="http://www.ietf.org/rfc/rfc2459.txt">
071: * http://www.ietf.org/rfc/rfc2459.txt </A>.
072: * <p>
073: * The ASN.1 definition of <code>tbsCertificate</code> is:
074: * <pre>
075: * TBSCertificate ::= SEQUENCE {
076: * version [0] EXPLICIT Version DEFAULT v1,
077: * serialNumber CertificateSerialNumber,
078: * signature AlgorithmIdentifier,
079: * issuer Name,
080: * validity Validity,
081: * subject Name,
082: * subjectPublicKeyInfo SubjectPublicKeyInfo,
083: * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
084: * -- If present, version must be v2 or v3
085: * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
086: * -- If present, version must be v2 or v3
087: * extensions [3] EXPLICIT Extensions OPTIONAL
088: * -- If present, version must be v3
089: * }
090: * </pre>
091: * <p>
092: * Certificates are instantiated using a certificate factory. The following is
093: * an example of how to instantiate an X.509 certificate:
094: * <pre>
095: * InputStream inStream = new FileInputStream("fileName-of-cert");
096: * CertificateFactory cf = CertificateFactory.getInstance("X.509");
097: * X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
098: * inStream.close();
099: * </pre>
100: *
101: * @author Hemma Prafullchandra
102: *
103: * @version 1.27
104: *
105: * @see Certificate
106: * @see CertificateFactory
107: * @see X509Extension
108: */
109:
110: public abstract class X509Certificate extends Certificate implements
111: X509Extension {
112:
113: private transient X500Principal subjectX500Principal,
114: issuerX500Principal;
115:
116: /**
117: * Constructor for X.509 certificates.
118: */
119: protected X509Certificate() {
120: super ("X.509");
121: }
122:
123: /**
124: * Checks that the certificate is currently valid. It is if
125: * the current date and time are within the validity period given in the
126: * certificate.
127: * <p>
128: * The validity period consists of two date/time values:
129: * the first and last dates (and times) on which the certificate
130: * is valid. It is defined in
131: * ASN.1 as:
132: * <pre>
133: * validity Validity<p>
134: * Validity ::= SEQUENCE {
135: * notBefore CertificateValidityDate,
136: * notAfter CertificateValidityDate }<p>
137: * CertificateValidityDate ::= CHOICE {
138: * utcTime UTCTime,
139: * generalTime GeneralizedTime }
140: * </pre>
141: *
142: * @exception CertificateExpiredException if the certificate has expired.
143: * @exception CertificateNotYetValidException if the certificate is not
144: * yet valid.
145: */
146: public abstract void checkValidity()
147: throws CertificateExpiredException,
148: CertificateNotYetValidException;
149:
150: /**
151: * Checks that the given date is within the certificate's
152: * validity period. In other words, this determines whether the
153: * certificate would be valid at the given date/time.
154: *
155: * @param date the Date to check against to see if this certificate
156: * is valid at that date/time.
157: *
158: * @exception CertificateExpiredException if the certificate has expired
159: * with respect to the <code>date</code> supplied.
160: * @exception CertificateNotYetValidException if the certificate is not
161: * yet valid with respect to the <code>date</code> supplied.
162: *
163: * @see #checkValidity()
164: */
165: public abstract void checkValidity(Date date)
166: throws CertificateExpiredException,
167: CertificateNotYetValidException;
168:
169: /**
170: * Gets the <code>version</code> (version number) value from the
171: * certificate.
172: * The ASN.1 definition for this is:
173: * <pre>
174: * version [0] EXPLICIT Version DEFAULT v1<p>
175: * Version ::= INTEGER { v1(0), v2(1), v3(2) }
176: * </pre>
177: * @return the version number, i.e. 1, 2 or 3.
178: */
179: public abstract int getVersion();
180:
181: /**
182: * Gets the <code>serialNumber</code> value from the certificate.
183: * The serial number is an integer assigned by the certification
184: * authority to each certificate. It must be unique for each
185: * certificate issued by a given CA (i.e., the issuer name and
186: * serial number identify a unique certificate).
187: * The ASN.1 definition for this is:
188: * <pre>
189: * serialNumber CertificateSerialNumber<p>
190: *
191: * CertificateSerialNumber ::= INTEGER
192: * </pre>
193: *
194: * @return the serial number.
195: */
196: public abstract BigInteger getSerialNumber();
197:
198: /**
199: * Gets the <code>issuer</code> (issuer distinguished name) value from
200: * the certificate. The issuer name identifies the entity that signed (and
201: * issued) the certificate.
202: *
203: * <p>The issuer name field contains an
204: * X.500 distinguished name (DN).
205: * The ASN.1 definition for this is:
206: * <pre>
207: * issuer Name<p>
208: *
209: * Name ::= CHOICE { RDNSequence }
210: * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
211: * RelativeDistinguishedName ::=
212: * SET OF AttributeValueAssertion
213: *
214: * AttributeValueAssertion ::= SEQUENCE {
215: * AttributeType,
216: * AttributeValue }
217: * AttributeType ::= OBJECT IDENTIFIER
218: * AttributeValue ::= ANY
219: * </pre>
220: * The <code>Name</code> describes a hierarchical name composed of
221: * attributes,
222: * such as country name, and corresponding values, such as US.
223: * The type of the <code>AttributeValue</code> component is determined by
224: * the <code>AttributeType</code>; in general it will be a
225: * <code>directoryString</code>. A <code>directoryString</code> is usually
226: * one of <code>PrintableString</code>,
227: * <code>TeletexString</code> or <code>UniversalString</code>.
228: *
229: * @return a Principal whose name is the issuer distinguished name.
230: */
231: public abstract Principal getIssuerDN();
232:
233: /**
234: * Returns the issuer (issuer distinguished name) value from the
235: * certificate as an <code>X500Principal</code>.
236: * <p>
237: * It is recommended that subclasses override this method to provide
238: * an efficient implementation.
239: *
240: * @return an <code>X500Principal</code> representing the issuer
241: * distinguished name
242: * @since 1.4
243: */
244: public X500Principal getIssuerX500Principal() {
245: if (issuerX500Principal == null) {
246: issuerX500Principal = X509CertImpl
247: .getIssuerX500Principal(this );
248: }
249: return issuerX500Principal;
250: }
251:
252: /**
253: * Gets the <code>subject</code> (subject distinguished name) value
254: * from the certificate. If the <code>subject</code> value is empty,
255: * then the <code>getName()</code> method of the returned
256: * <code>Principal</code> object returns an empty string ("").
257: *
258: * <p> The ASN.1 definition for this is:
259: * <pre>
260: * subject Name
261: * </pre>
262: *
263: * <p>See {@link #getIssuerDN() getIssuerDN} for <code>Name</code>
264: * and other relevant definitions.
265: *
266: * @return a Principal whose name is the subject name.
267: */
268: public abstract Principal getSubjectDN();
269:
270: /**
271: * Returns the subject (subject distinguished name) value from the
272: * certificate as an <code>X500Principal</code>. If the subject value
273: * is empty, then the <code>getName()</code> method of the returned
274: * <code>X500Principal</code> object returns an empty string ("").
275: * <p>
276: * It is recommended that subclasses override this method to provide
277: * an efficient implementation.
278: *
279: * @return an <code>X500Principal</code> representing the subject
280: * distinguished name
281: * @since 1.4
282: */
283: public X500Principal getSubjectX500Principal() {
284: if (subjectX500Principal == null) {
285: subjectX500Principal = X509CertImpl
286: .getSubjectX500Principal(this );
287: }
288: return subjectX500Principal;
289: }
290:
291: /**
292: * Gets the <code>notBefore</code> date from the validity period of
293: * the certificate.
294: * The relevant ASN.1 definitions are:
295: * <pre>
296: * validity Validity<p>
297: *
298: * Validity ::= SEQUENCE {
299: * notBefore CertificateValidityDate,
300: * notAfter CertificateValidityDate }<p>
301: * CertificateValidityDate ::= CHOICE {
302: * utcTime UTCTime,
303: * generalTime GeneralizedTime }
304: * </pre>
305: *
306: * @return the start date of the validity period.
307: * @see #checkValidity
308: */
309: public abstract Date getNotBefore();
310:
311: /**
312: * Gets the <code>notAfter</code> date from the validity period of
313: * the certificate. See {@link #getNotBefore() getNotBefore}
314: * for relevant ASN.1 definitions.
315: *
316: * @return the end date of the validity period.
317: * @see #checkValidity
318: */
319: public abstract Date getNotAfter();
320:
321: /**
322: * Gets the DER-encoded certificate information, the
323: * <code>tbsCertificate</code> from this certificate.
324: * This can be used to verify the signature independently.
325: *
326: * @return the DER-encoded certificate information.
327: * @exception CertificateEncodingException if an encoding error occurs.
328: */
329: public abstract byte[] getTBSCertificate()
330: throws CertificateEncodingException;
331:
332: /**
333: * Gets the <code>signature</code> value (the raw signature bits) from
334: * the certificate.
335: * The ASN.1 definition for this is:
336: * <pre>
337: * signature BIT STRING
338: * </pre>
339: *
340: * @return the signature.
341: */
342: public abstract byte[] getSignature();
343:
344: /**
345: * Gets the signature algorithm name for the certificate
346: * signature algorithm. An example is the string "SHA-1/DSA".
347: * The ASN.1 definition for this is:
348: * <pre>
349: * signatureAlgorithm AlgorithmIdentifier<p>
350: * AlgorithmIdentifier ::= SEQUENCE {
351: * algorithm OBJECT IDENTIFIER,
352: * parameters ANY DEFINED BY algorithm OPTIONAL }
353: * -- contains a value of the type
354: * -- registered for use with the
355: * -- algorithm object identifier value
356: * </pre>
357: *
358: * <p>The algorithm name is determined from the <code>algorithm</code>
359: * OID string.
360: *
361: * @return the signature algorithm name.
362: */
363: public abstract String getSigAlgName();
364:
365: /**
366: * Gets the signature algorithm OID string from the certificate.
367: * An OID is represented by a set of nonnegative whole numbers separated
368: * by periods.
369: * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
370: * with DSA signature algorithm, as per RFC 2459.
371: *
372: * <p>See {@link #getSigAlgName() getSigAlgName} for
373: * relevant ASN.1 definitions.
374: *
375: * @return the signature algorithm OID string.
376: */
377: public abstract String getSigAlgOID();
378:
379: /**
380: * Gets the DER-encoded signature algorithm parameters from this
381: * certificate's signature algorithm. In most cases, the signature
382: * algorithm parameters are null; the parameters are usually
383: * supplied with the certificate's public key.
384: * If access to individual parameter values is needed then use
385: * {@link java.security.AlgorithmParameters AlgorithmParameters}
386: * and instantiate with the name returned by
387: * {@link #getSigAlgName() getSigAlgName}.
388: *
389: * <p>See {@link #getSigAlgName() getSigAlgName} for
390: * relevant ASN.1 definitions.
391: *
392: * @return the DER-encoded signature algorithm parameters, or
393: * null if no parameters are present.
394: */
395: public abstract byte[] getSigAlgParams();
396:
397: /**
398: * Gets the <code>issuerUniqueID</code> value from the certificate.
399: * The issuer unique identifier is present in the certificate
400: * to handle the possibility of reuse of issuer names over time.
401: * RFC 2459 recommends that names not be reused and that
402: * conforming certificates not make use of unique identifiers.
403: * Applications conforming to that profile should be capable of
404: * parsing unique identifiers and making comparisons.
405: *
406: * <p>The ASN.1 definition for this is:
407: * <pre>
408: * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL<p>
409: * UniqueIdentifier ::= BIT STRING
410: * </pre>
411: *
412: * @return the issuer unique identifier or null if it is not
413: * present in the certificate.
414: */
415: public abstract boolean[] getIssuerUniqueID();
416:
417: /**
418: * Gets the <code>subjectUniqueID</code> value from the certificate.
419: *
420: * <p>The ASN.1 definition for this is:
421: * <pre>
422: * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL<p>
423: * UniqueIdentifier ::= BIT STRING
424: * </pre>
425: *
426: * @return the subject unique identifier or null if it is not
427: * present in the certificate.
428: */
429: public abstract boolean[] getSubjectUniqueID();
430:
431: /**
432: * Gets a boolean array representing bits of
433: * the <code>KeyUsage</code> extension, (OID = 2.5.29.15).
434: * The key usage extension defines the purpose (e.g., encipherment,
435: * signature, certificate signing) of the key contained in the
436: * certificate.
437: * The ASN.1 definition for this is:
438: * <pre>
439: * KeyUsage ::= BIT STRING {
440: * digitalSignature (0),
441: * nonRepudiation (1),
442: * keyEncipherment (2),
443: * dataEncipherment (3),
444: * keyAgreement (4),
445: * keyCertSign (5),
446: * cRLSign (6),
447: * encipherOnly (7),
448: * decipherOnly (8) }
449: * </pre>
450: * RFC 2459 recommends that when used, this be marked
451: * as a critical extension.
452: *
453: * @return the KeyUsage extension of this certificate, represented as
454: * an array of booleans. The order of KeyUsage values in the array is
455: * the same as in the above ASN.1 definition. The array will contain a
456: * value for each KeyUsage defined above. If the KeyUsage list encoded
457: * in the certificate is longer than the above list, it will not be
458: * truncated. Returns null if this certificate does not
459: * contain a KeyUsage extension.
460: */
461: public abstract boolean[] getKeyUsage();
462:
463: /**
464: * Gets an unmodifiable list of Strings representing the OBJECT
465: * IDENTIFIERs of the <code>ExtKeyUsageSyntax</code> field of the
466: * extended key usage extension, (OID = 2.5.29.37). It indicates
467: * one or more purposes for which the certified public key may be
468: * used, in addition to or in place of the basic purposes
469: * indicated in the key usage extension field. The ASN.1
470: * definition for this is:
471: * <pre>
472: * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId<p>
473: *
474: * KeyPurposeId ::= OBJECT IDENTIFIER<p>
475: * </pre>
476: *
477: * Key purposes may be defined by any organization with a
478: * need. Object identifiers used to identify key purposes shall be
479: * assigned in accordance with IANA or ITU-T Rec. X.660 |
480: * ISO/IEC/ITU 9834-1.
481: * <p>
482: * This method was added to version 1.4 of the Java 2 Platform Standard
483: * Edition. In order to maintain backwards compatibility with existing
484: * service providers, this method is not <code>abstract</code>
485: * and it provides a default implementation. Subclasses
486: * should override this method with a correct implementation.
487: *
488: * @return the ExtendedKeyUsage extension of this certificate,
489: * as an unmodifiable list of object identifiers represented
490: * as Strings. Returns null if this certificate does not
491: * contain an ExtendedKeyUsage extension.
492: * @throws CertificateParsingException if the extension cannot be decoded
493: * @since 1.4
494: */
495: public List getExtendedKeyUsage()
496: throws CertificateParsingException {
497: return X509CertImpl.getExtendedKeyUsage(this );
498: }
499:
500: /**
501: * Gets the certificate constraints path length from the
502: * critical <code>BasicConstraints</code> extension, (OID = 2.5.29.19).
503: * <p>
504: * The basic constraints extension identifies whether the subject
505: * of the certificate is a Certificate Authority (CA) and
506: * how deep a certification path may exist through that CA. The
507: * <code>pathLenConstraint</code> field (see below) is meaningful
508: * only if <code>cA</code> is set to TRUE. In this case, it gives the
509: * maximum number of CA certificates that may follow this certificate in a
510: * certification path. A value of zero indicates that only an end-entity
511: * certificate may follow in the path.
512: * <p>
513: * Note that for RFC 2459 this extension is always marked
514: * critical if <code>cA</code> is TRUE, meaning this certificate belongs
515: * to a Certificate Authority.
516: * <p>
517: * The ASN.1 definition for this is:
518: * <pre>
519: * BasicConstraints ::= SEQUENCE {
520: * cA BOOLEAN DEFAULT FALSE,
521: * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
522: * </pre>
523: *
524: * @return the value of <code>pathLenConstraint</code> if the
525: * BasicConstraints extension is present in the certificate and the
526: * subject of the certificate is a CA, otherwise -1.
527: * If the subject of the certificate is a CA and
528: * <code>pathLenConstraint</code> does not appear,
529: * <code>Integer.MAX_VALUE</code> is returned to indicate that there is no
530: * limit to the allowed length of the certification path.
531: */
532: public abstract int getBasicConstraints();
533:
534: /**
535: * Gets an immutable collection of subject alternative names from the
536: * <code>SubjectAltName</code> extension, (OID = 2.5.29.17).
537: * <p>
538: * The ASN.1 definition of the <code>SubjectAltName</code> extension is:
539: * <pre>
540: * SubjectAltName ::= GeneralNames
541: *
542: * GeneralNames :: = SEQUENCE SIZE (1..MAX) OF GeneralName
543: *
544: * GeneralName ::= CHOICE {
545: * otherName [0] OtherName,
546: * rfc822Name [1] IA5String,
547: * dNSName [2] IA5String,
548: * x400Address [3] ORAddress,
549: * directoryName [4] Name,
550: * ediPartyName [5] EDIPartyName,
551: * uniformResourceIdentifier [6] IA5String,
552: * iPAddress [7] OCTET STRING,
553: * registeredID [8] OBJECT IDENTIFIER}
554: * </pre>
555: * <p>
556: * If this certificate does not contain a <code>SubjectAltName</code>
557: * extension, <code>null</code> is returned. Otherwise, a
558: * <code>Collection</code> is returned with an entry representing each
559: * <code>GeneralName</code> included in the extension. Each entry is a
560: * <code>List</code> whose first entry is an <code>Integer</code>
561: * (the name type, 0-8) and whose second entry is a <code>String</code>
562: * or a byte array (the name, in string or ASN.1 DER encoded form,
563: * respectively).
564: * <p>
565: * RFC 822, DNS, and URI names are returned as <code>String</code>s,
566: * using the well-established string formats for those types (subject to
567: * the restrictions included in RFC 2459). IPv4 address names are
568: * returned using dotted quad notation. IPv6 address names are returned
569: * in the form "a1:a2:...:a8", where a1-a8 are hexadecimal values
570: * representing the eight 16-bit pieces of the address. OID names are
571: * returned as <code>String</code>s represented as a series of nonnegative
572: * integers separated by periods. And directory names (distinguished names)
573: * are returned in RFC 2253 string format. No standard string format is
574: * defined for otherNames, X.400 names, EDI party names, or any
575: * other type of names. They are returned as byte arrays
576: * containing the ASN.1 DER encoded form of the name.
577: * <p>
578: * Note that the <code>Collection</code> returned may contain more
579: * than one name of the same type. Also, note that the returned
580: * <code>Collection</code> is immutable and any entries containing byte
581: * arrays are cloned to protect against subsequent modifications.
582: * <p>
583: * This method was added to version 1.4 of the Java 2 Platform Standard
584: * Edition. In order to maintain backwards compatibility with existing
585: * service providers, this method is not <code>abstract</code>
586: * and it provides a default implementation. Subclasses
587: * should override this method with a correct implementation.
588: *
589: * @return an immutable <code>Collection</code> of subject alternative
590: * names (or <code>null</code>)
591: * @throws CertificateParsingException if the extension cannot be decoded
592: * @since 1.4
593: */
594: public Collection getSubjectAlternativeNames()
595: throws CertificateParsingException {
596: return X509CertImpl.getSubjectAlternativeNames(this );
597: }
598:
599: /**
600: * Gets an immutable collection of issuer alternative names from the
601: * <code>IssuerAltName</code> extension, (OID = 2.5.29.18).
602: * <p>
603: * The ASN.1 definition of the <code>IssuerAltName</code> extension is:
604: * <pre>
605: * IssuerAltName ::= GeneralNames
606: * </pre>
607: * The ASN.1 definition of <code>GeneralNames</code> is defined
608: * in {@link #getSubjectAlternativeNames getSubjectAlternativeNames}.
609: * <p>
610: * If this certificate does not contain an <code>IssuerAltName</code>
611: * extension, <code>null</code> is returned. Otherwise, a
612: * <code>Collection</code> is returned with an entry representing each
613: * <code>GeneralName</code> included in the extension. Each entry is a
614: * <code>List</code> whose first entry is an <code>Integer</code>
615: * (the name type, 0-8) and whose second entry is a <code>String</code>
616: * or a byte array (the name, in string or ASN.1 DER encoded form,
617: * respectively). For more details about the formats used for each
618: * name type, see the <code>getSubjectAlternativeNames</code> method.
619: * <p>
620: * Note that the <code>Collection</code> returned may contain more
621: * than one name of the same type. Also, note that the returned
622: * <code>Collection</code> is immutable and any entries containing byte
623: * arrays are cloned to protect against subsequent modifications.
624: * <p>
625: * This method was added to version 1.4 of the Java 2 Platform Standard
626: * Edition. In order to maintain backwards compatibility with existing
627: * service providers, this method is not <code>abstract</code>
628: * and it provides a default implementation. Subclasses
629: * should override this method with a correct implementation.
630: *
631: * @return an immutable <code>Collection</code> of issuer alternative
632: * names (or <code>null</code>)
633: * @throws CertificateParsingException if the extension cannot be decoded
634: * @since 1.4
635: */
636: public Collection getIssuerAlternativeNames()
637: throws CertificateParsingException {
638: return X509CertImpl.getIssuerAlternativeNames(this);
639: }
640: }
|