1 module hunt.security.cert.CertificateFactory; 2 3 import hunt.security.cert.Certificate; 4 import hunt.security.cert.CertificateFactorySpi; 5 import hunt.security.cert.CertPath; 6 import hunt.security.cert.CRL; 7 8 import hunt.security.Provider; 9 10 import hunt.collection; 11 import hunt.stream.Common; 12 13 import hunt.Exceptions; 14 15 16 17 /** 18 * This class defines the functionality of a certificate factory, which is 19 * used to generate certificate, certification path ({@code CertPath}) 20 * and certificate revocation list (CRL) objects from their encodings. 21 * 22 * <p>For encodings consisting of multiple certificates, use 23 * {@code generateCertificates} when you want to 24 * parse a collection of possibly unrelated certificates. Otherwise, 25 * use {@code generateCertPath} when you want to generate 26 * a {@code CertPath} (a certificate chain) and subsequently 27 * validate it with a {@code CertPathValidator}. 28 * 29 * <p>A certificate factory for X.509 must return certificates that are an 30 * instance of {@code java.security.cert.X509Certificate}, and CRLs 31 * that are an instance of {@code java.security.cert.X509CRL}. 32 * 33 * <p>The following example reads a file with Base64 encoded certificates, 34 * which are each bounded at the beginning by -----BEGIN CERTIFICATE-----, and 35 * bounded at the end by -----END CERTIFICATE-----. We convert the 36 * {@code FileInputStream} (which does not support {@code mark} 37 * and {@code reset}) to a {@code BufferedInputStream} (which 38 * supports those methods), so that each call to 39 * {@code generateCertificate} consumes only one certificate, and the 40 * read position of the input stream is positioned to the next certificate in 41 * the file: 42 * 43 * <pre>{@code 44 * FileInputStream fis = new FileInputStream(filename); 45 * BufferedInputStream bis = new BufferedInputStream(fis); 46 * 47 * CertificateFactory cf = CertificateFactory.getInstance("X.509"); 48 * 49 * while (bis.available() > 0) { 50 * Certificate cert = cf.generateCertificate(bis); 51 * System.out.println(cert.toString()); 52 * } 53 * }</pre> 54 * 55 * <p>The following example parses a PKCS#7-formatted certificate reply stored 56 * in a file and extracts all the certificates from it: 57 * 58 * <pre> 59 * FileInputStream fis = new FileInputStream(filename); 60 * CertificateFactory cf = CertificateFactory.getInstance("X.509"); 61 * Collection c = cf.generateCertificates(fis); 62 * Iterator i = c.iterator(); 63 * while (i.hasNext()) { 64 * Certificate cert = (Certificate)i.next(); 65 * System.out.println(cert); 66 * } 67 * </pre> 68 * 69 * <p> Every implementation of the Java platform is required to support the 70 * following standard {@code CertificateFactory} type: 71 * <ul> 72 * <li>{@code X.509}</li> 73 * </ul> 74 * and the following standard {@code CertPath} encodings: 75 * <ul> 76 * <li>{@code PKCS7}</li> 77 * <li>{@code PkiPath}</li> 78 * </ul> 79 * The type and encodings are described in the <a href= 80 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory"> 81 * CertificateFactory section</a> and the <a href= 82 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings"> 83 * CertPath Encodings section</a> of the 84 * Java Cryptography Architecture Standard Algorithm Name Documentation. 85 * Consult the release documentation for your implementation to see if any 86 * other types or encodings are supported. 87 * 88 * @author Hemma Prafullchandra 89 * @author Jan Luehe 90 * @author Sean Mullan 91 * 92 * @see Certificate 93 * @see X509Certificate 94 * @see CertPath 95 * @see CRL 96 * @see X509CRL 97 * 98 * @since 1.2 99 */ 100 101 class CertificateFactory { 102 103 // The certificate type 104 private string type; 105 106 // The provider 107 private Provider provider; 108 109 // The provider implementation 110 private CertificateFactorySpi certFacSpi; 111 112 /** 113 * Creates a CertificateFactory object of the given type, and encapsulates 114 * the given provider implementation (SPI object) in it. 115 * 116 * @param certFacSpi the provider implementation. 117 * @param provider the provider. 118 * @param type the certificate type. 119 */ 120 protected this(CertificateFactorySpi certFacSpi, 121 Provider provider, string type) 122 { 123 this.certFacSpi = certFacSpi; 124 this.provider = provider; 125 this.type = type; 126 } 127 128 /** 129 * Returns a certificate factory object that implements the 130 * specified certificate type. 131 * 132 * <p> This method traverses the list of registered security Providers, 133 * starting with the most preferred Provider. 134 * A new CertificateFactory object encapsulating the 135 * CertificateFactorySpi implementation from the first 136 * Provider that supports the specified type is returned. 137 * 138 * <p> Note that the list of registered providers may be retrieved via 139 * the {@link Security#getProviders() Security.getProviders()} method. 140 * 141 * @param type the name of the requested certificate type. 142 * See the CertificateFactory section in the <a href= 143 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory"> 144 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 145 * for information about standard certificate types. 146 * 147 * @return a certificate factory object for the specified type. 148 * 149 * @exception CertificateException if no Provider supports a 150 * CertificateFactorySpi implementation for the 151 * specified type. 152 * 153 * @see java.security.Provider 154 */ 155 static final CertificateFactory getInstance(string type) { 156 try { 157 return new CertificateFactory(getFactorySpi(type), 158 null, type); 159 } catch (NoSuchAlgorithmException e) { 160 throw new CertificateException(type ~ " not found", e); 161 } 162 } 163 164 static CertificateFactorySpi getFactorySpi(string type) 165 { 166 if(type == "X.509") 167 { 168 import hunt.security.x509.X509Factory; 169 return new X509Factory(); 170 } 171 else 172 throw new NotSupportedException(type); 173 } 174 175 /** 176 * Returns a certificate factory object for the specified 177 * certificate type. 178 * 179 * <p> A new CertificateFactory object encapsulating the 180 * CertificateFactorySpi implementation from the specified provider 181 * is returned. The specified provider must be registered 182 * in the security provider list. 183 * 184 * <p> Note that the list of registered providers may be retrieved via 185 * the {@link Security#getProviders() Security.getProviders()} method. 186 * 187 * @param type the certificate type. 188 * See the CertificateFactory section in the <a href= 189 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory"> 190 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 191 * for information about standard certificate types. 192 * 193 * @param provider the name of the provider. 194 * 195 * @return a certificate factory object for the specified type. 196 * 197 * @exception CertificateException if a CertificateFactorySpi 198 * implementation for the specified algorithm is not 199 * available from the specified provider. 200 * 201 * @exception NoSuchProviderException if the specified provider is not 202 * registered in the security provider list. 203 * 204 * @exception IllegalArgumentException if the provider name is null 205 * or empty. 206 * 207 * @see java.security.Provider 208 */ 209 // static final CertificateFactory getInstance(string type, 210 // string provider) { 211 // try { 212 // Instance instance = GetInstance.getInstance("CertificateFactory", 213 // CertificateFactorySpi.class, type, provider); 214 // return new CertificateFactory((CertificateFactorySpi)instance.impl, 215 // instance.provider, type); 216 // } catch (NoSuchAlgorithmException e) { 217 // throw new CertificateException(type ~ " not found", e); 218 // } 219 // } 220 221 /** 222 * Returns a certificate factory object for the specified 223 * certificate type. 224 * 225 * <p> A new CertificateFactory object encapsulating the 226 * CertificateFactorySpi implementation from the specified Provider 227 * object is returned. Note that the specified Provider object 228 * does not have to be registered in the provider list. 229 * 230 * @param type the certificate type. 231 * See the CertificateFactory section in the <a href= 232 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory"> 233 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 234 * for information about standard certificate types. 235 * @param provider the provider. 236 * 237 * @return a certificate factory object for the specified type. 238 * 239 * @exception CertificateException if a CertificateFactorySpi 240 * implementation for the specified algorithm is not available 241 * from the specified Provider object. 242 * 243 * @exception IllegalArgumentException if the {@code provider} is 244 * null. 245 * 246 * @see java.security.Provider 247 * 248 * @since 1.4 249 */ 250 // static final CertificateFactory getInstance(string type, 251 // Provider provider) throws CertificateException { 252 // try { 253 // Instance instance = GetInstance.getInstance("CertificateFactory", 254 // CertificateFactorySpi.class, type, provider); 255 // return new CertificateFactory((CertificateFactorySpi)instance.impl, 256 // instance.provider, type); 257 // } catch (NoSuchAlgorithmException e) { 258 // throw new CertificateException(type ~ " not found", e); 259 // } 260 // } 261 262 /** 263 * Returns the provider of this certificate factory. 264 * 265 * @return the provider of this certificate factory. 266 */ 267 final Provider getProvider() { 268 return this.provider; 269 } 270 271 /** 272 * Returns the name of the certificate type associated with this 273 * certificate factory. 274 * 275 * @return the name of the certificate type associated with this 276 * certificate factory. 277 */ 278 final string getType() { 279 return this.type; 280 } 281 282 /** 283 * Generates a certificate object and initializes it with 284 * the data read from the input stream {@code inStream}. 285 * 286 * <p>In order to take advantage of the specialized certificate format 287 * supported by this certificate factory, 288 * the returned certificate object can be typecast to the corresponding 289 * certificate class. For example, if this certificate 290 * factory implements X.509 certificates, the returned certificate object 291 * can be typecast to the {@code X509Certificate} class. 292 * 293 * <p>In the case of a certificate factory for X.509 certificates, the 294 * certificate provided in {@code inStream} must be DER-encoded and 295 * may be supplied in binary or printable (Base64) encoding. If the 296 * certificate is provided in Base64 encoding, it must be bounded at 297 * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at 298 * the end by -----END CERTIFICATE-----. 299 * 300 * <p>Note that if the given input stream does not support 301 * {@link java.io.InputStream#mark(int) mark} and 302 * {@link java.io.InputStream#reset() reset}, this method will 303 * consume the entire input stream. Otherwise, each call to this 304 * method consumes one certificate and the read position of the 305 * input stream is positioned to the next available byte after 306 * the inherent end-of-certificate marker. If the data in the input stream 307 * does not contain an inherent end-of-certificate marker (other 308 * than EOF) and there is trailing data after the certificate is parsed, a 309 * {@code CertificateException} is thrown. 310 * 311 * @param inStream an input stream with the certificate data. 312 * 313 * @return a certificate object initialized with the data 314 * from the input stream. 315 * 316 * @exception CertificateException on parsing errors. 317 */ 318 final Certificate generateCertificate(InputStream inStream) 319 { 320 return certFacSpi.engineGenerateCertificate(inStream); 321 } 322 323 /** 324 * Returns an iteration of the {@code CertPath} encodings supported 325 * by this certificate factory, with the default encoding first. See 326 * the CertPath Encodings section in the <a href= 327 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings"> 328 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 329 * for information about standard encoding names and their formats. 330 * <p> 331 * Attempts to modify the returned {@code Iterator} via its 332 * {@code remove} method result in an 333 * {@code UnsupportedOperationException}. 334 * 335 * @return an {@code Iterator} over the names of the supported 336 * {@code CertPath} encodings (as {@code string}s) 337 * @since 1.4 338 */ 339 final Iterator!string getCertPathEncodings() { 340 return certFacSpi.engineGetCertPathEncodings(); 341 } 342 343 /** 344 * Generates a {@code CertPath} object and initializes it with 345 * the data read from the {@code InputStream} inStream. The data 346 * is assumed to be in the default encoding. The name of the default 347 * encoding is the first element of the {@code Iterator} returned by 348 * the {@link #getCertPathEncodings getCertPathEncodings} method. 349 * 350 * @param inStream an {@code InputStream} containing the data 351 * @return a {@code CertPath} initialized with the data from the 352 * {@code InputStream} 353 * @exception CertificateException if an exception occurs while decoding 354 * @since 1.4 355 */ 356 final CertPath generateCertPath(InputStream inStream) 357 { 358 return certFacSpi.engineGenerateCertPath(inStream); 359 } 360 361 /** 362 * Generates a {@code CertPath} object and initializes it with 363 * the data read from the {@code InputStream} inStream. The data 364 * is assumed to be in the specified encoding. See 365 * the CertPath Encodings section in the <a href= 366 * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings"> 367 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 368 * for information about standard encoding names and their formats. 369 * 370 * @param inStream an {@code InputStream} containing the data 371 * @param encoding the encoding used for the data 372 * @return a {@code CertPath} initialized with the data from the 373 * {@code InputStream} 374 * @exception CertificateException if an exception occurs while decoding or 375 * the encoding requested is not supported 376 * @since 1.4 377 */ 378 final CertPath generateCertPath(InputStream inStream, string encoding) 379 { 380 return certFacSpi.engineGenerateCertPath(inStream, encoding); 381 } 382 383 /** 384 * Generates a {@code CertPath} object and initializes it with 385 * a {@code List} of {@code Certificate}s. 386 * <p> 387 * The certificates supplied must be of a type supported by the 388 * {@code CertificateFactory}. They will be copied out of the supplied 389 * {@code List} object. 390 * 391 * @param certificates a {@code List} of {@code Certificate}s 392 * @return a {@code CertPath} initialized with the supplied list of 393 * certificates 394 * @exception CertificateException if an exception occurs 395 * @since 1.4 396 */ 397 final CertPath generateCertPath(List!Certificate certificates) 398 { 399 return certFacSpi.engineGenerateCertPath(certificates); 400 } 401 402 /** 403 * Returns a (possibly empty) collection view of the certificates read 404 * from the given input stream {@code inStream}. 405 * 406 * <p>In order to take advantage of the specialized certificate format 407 * supported by this certificate factory, each element in 408 * the returned collection view can be typecast to the corresponding 409 * certificate class. For example, if this certificate 410 * factory implements X.509 certificates, the elements in the returned 411 * collection can be typecast to the {@code X509Certificate} class. 412 * 413 * <p>In the case of a certificate factory for X.509 certificates, 414 * {@code inStream} may contain a sequence of DER-encoded certificates 415 * in the formats described for 416 * {@link #generateCertificate(java.io.InputStream) generateCertificate}. 417 * In addition, {@code inStream} may contain a PKCS#7 certificate 418 * chain. This is a PKCS#7 <i>SignedData</i> object, with the only 419 * significant field being <i>certificates</i>. In particular, the 420 * signature and the contents are ignored. This format allows multiple 421 * certificates to be downloaded at once. If no certificates are present, 422 * an empty collection is returned. 423 * 424 * <p>Note that if the given input stream does not support 425 * {@link java.io.InputStream#mark(int) mark} and 426 * {@link java.io.InputStream#reset() reset}, this method will 427 * consume the entire input stream. 428 * 429 * @param inStream the input stream with the certificates. 430 * 431 * @return a (possibly empty) collection view of 432 * java.security.cert.Certificate objects 433 * initialized with the data from the input stream. 434 * 435 * @exception CertificateException on parsing errors. 436 */ 437 final Collection!Certificate generateCertificates(InputStream inStream) { 438 return certFacSpi.engineGenerateCertificates(inStream); 439 } 440 441 /** 442 * Generates a certificate revocation list (CRL) object and initializes it 443 * with the data read from the input stream {@code inStream}. 444 * 445 * <p>In order to take advantage of the specialized CRL format 446 * supported by this certificate factory, 447 * the returned CRL object can be typecast to the corresponding 448 * CRL class. For example, if this certificate 449 * factory implements X.509 CRLs, the returned CRL object 450 * can be typecast to the {@code X509CRL} class. 451 * 452 * <p>Note that if the given input stream does not support 453 * {@link java.io.InputStream#mark(int) mark} and 454 * {@link java.io.InputStream#reset() reset}, this method will 455 * consume the entire input stream. Otherwise, each call to this 456 * method consumes one CRL and the read position of the input stream 457 * is positioned to the next available byte after the inherent 458 * end-of-CRL marker. If the data in the 459 * input stream does not contain an inherent end-of-CRL marker (other 460 * than EOF) and there is trailing data after the CRL is parsed, a 461 * {@code CRLException} is thrown. 462 * 463 * @param inStream an input stream with the CRL data. 464 * 465 * @return a CRL object initialized with the data 466 * from the input stream. 467 * 468 * @exception CRLException on parsing errors. 469 */ 470 final CRL generateCRL(InputStream inStream) { 471 return certFacSpi.engineGenerateCRL(inStream); 472 } 473 474 /** 475 * Returns a (possibly empty) collection view of the CRLs read 476 * from the given input stream {@code inStream}. 477 * 478 * <p>In order to take advantage of the specialized CRL format 479 * supported by this certificate factory, each element in 480 * the returned collection view can be typecast to the corresponding 481 * CRL class. For example, if this certificate 482 * factory implements X.509 CRLs, the elements in the returned 483 * collection can be typecast to the {@code X509CRL} class. 484 * 485 * <p>In the case of a certificate factory for X.509 CRLs, 486 * {@code inStream} may contain a sequence of DER-encoded CRLs. 487 * In addition, {@code inStream} may contain a PKCS#7 CRL 488 * set. This is a PKCS#7 <i>SignedData</i> object, with the only 489 * significant field being <i>crls</i>. In particular, the 490 * signature and the contents are ignored. This format allows multiple 491 * CRLs to be downloaded at once. If no CRLs are present, 492 * an empty collection is returned. 493 * 494 * <p>Note that if the given input stream does not support 495 * {@link java.io.InputStream#mark(int) mark} and 496 * {@link java.io.InputStream#reset() reset}, this method will 497 * consume the entire input stream. 498 * 499 * @param inStream the input stream with the CRLs. 500 * 501 * @return a (possibly empty) collection view of 502 * java.security.cert.CRL objects initialized with the data from the input 503 * stream. 504 * 505 * @exception CRLException on parsing errors. 506 */ 507 final Collection!CRL generateCRLs(InputStream inStream) { 508 return certFacSpi.engineGenerateCRLs(inStream); 509 } 510 }