Changeset 79baf70


Ignore:
Timestamp:
Feb 25, 2018 2:17:01 PM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
4c02c1f
Parents:
622c680
Message:

Crypto: Add support for more alt names in certs (tickets #2159, #2160)
Set alt names for console cert
Use utils to validate console IP addresses

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java

    r622c680 r79baf70  
    4242import net.i2p.util.I2PSSLSocketFactory;
    4343import net.i2p.util.SystemVersion;
     44
     45import org.apache.http.conn.util.InetAddressUtils;
    4446
    4547import org.eclipse.jetty.security.HashLoginService;
     
    517519                        // Test before we add the connector, because Jetty 6 won't start if any of the
    518520                        // connectors are bad
    519                         InetAddress test = InetAddress.getByName(host);
    520                         if ((!hasIPV6) && (!(test instanceof Inet4Address)))
     521                        if ((!hasIPV6) && InetAddressUtils.isIPv6Address(host))
    521522                            throw new IOException("IPv6 addresses unsupported");
    522                         if ((!hasIPV4) && (test instanceof Inet4Address))
     523                        if ((!hasIPV4) && InetAddressUtils.isIPv4Address(host))
    523524                            throw new IOException("IPv4 addresses unsupported");
    524525                        ServerSocket testSock = null;
     
    527528                            // possibly due to %scope_id ???
    528529                            // https://issues.apache.org/jira/browse/ZOOKEEPER-667
    529                             //testSock = new ServerSocket(0, 0, test);
    530530                            // so do exactly what Jetty does in SelectChannelConnector.open()
    531531                            testSock = new ServerSocket();
     
    575575            if (sslPort > 0) {
    576576                File keyStore = new File(_context.getConfigDir(), "keystore/console.ks");
    577                 if (verifyKeyStore(keyStore)) {
     577                // Put the list of hosts together early, so we can put it in the selfsigned cert.
     578                StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
     579                Set<String> altNames = new HashSet<String>(4);
     580                while (tok.hasMoreTokens()) {
     581                    String s = tok.nextToken().trim();
     582                    if (!s.equals("0.0.0.0") && !s.equals("::") &&
     583                        !s.equals("0:0:0:0:0:0:0:0"))
     584                        altNames.add(s);
     585                }
     586                String allowed = _context.getProperty(PROP_ALLOWED_HOSTS);
     587                if (allowed != null) {
     588                    tok = new StringTokenizer(allowed, " ,");
     589                    while (tok.hasMoreTokens()) {
     590                        altNames.add(tok.nextToken().trim());
     591                    }
     592                }
     593                if (verifyKeyStore(keyStore, altNames)) {
    578594                    // the keystore path and password
    579595                    SslContextFactory sslFactory = new SslContextFactory(keyStore.getAbsolutePath());
     
    586602                                                      new String[I2PSSLSocketFactory.EXCLUDE_CIPHERS.size()]));
    587603                    List<String> hosts = new ArrayList<String>(2);
    588                     StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
     604                    tok = new StringTokenizer(_sslListenHost, " ,");
    589605                    while (tok.hasMoreTokens()) {
    590606                        String host = tok.nextToken().trim();
     
    593609                            // Test before we add the connector, because Jetty 6 won't start if any of the
    594610                            // connectors are bad
    595                             InetAddress test = InetAddress.getByName(host);
    596                             if ((!hasIPV6) && (!(test instanceof Inet4Address)))
     611                            if ((!hasIPV6) && InetAddressUtils.isIPv6Address(host))
    597612                                throw new IOException("IPv6 addresses unsupported");
    598                             if ((!hasIPV4) && (test instanceof Inet4Address))
     613                            if ((!hasIPV4) && InetAddressUtils.isIPv4Address(host))
    599614                                throw new IOException("IPv4 addresses unsupported");
    600615                            ServerSocket testSock = null;
    601616                            try {
    602617                                // see comments above
    603                                 //testSock = new ServerSocket(0, 0, test);
    604618                                testSock = new ServerSocket();
    605619                                InetSocketAddress isa = new InetSocketAddress(host, 0);
     
    840854     * @since 0.8.3
    841855     */
    842     private boolean verifyKeyStore(File ks) {
     856    private boolean verifyKeyStore(File ks, Set<String> altNames) {
    843857        if (ks.exists()) {
    844858            boolean rv = _context.getProperty(PROP_KEY_PASSWORD) != null;
     
    847861            return rv;
    848862        }
    849         return createKeyStore(ks);
     863        return createKeyStore(ks, altNames);
    850864    }
    851865
    852866
    853867    /**
    854      * Call out to keytool to create a new keystore with a keypair in it.
    855      * Trying to do this programatically is a nightmare, requiring either BouncyCastle
    856      * libs or using proprietary Sun libs, and it's a huge mess.
     868     * Create a new keystore with a keypair in it.
    857869     *
    858870     * @return success
    859871     * @since 0.8.3
    860872     */
    861     private boolean createKeyStore(File ks) {
     873    private boolean createKeyStore(File ks, Set<String> altNames) {
    862874        // make a random 48 character password (30 * 8 / 5)
    863875        String keyPassword = KeyStoreUtil.randomString();
    864876        String cname = "localhost";
    865         boolean success = KeyStoreUtil.createKeys(ks, "console", cname, "Console", keyPassword);
     877        boolean success = KeyStoreUtil.createKeys(ks, "console", cname, altNames, "Console", keyPassword);
    866878        if (success) {
    867879            success = ks.exists();
     
    884896        if (success) {
    885897            System.err.println("Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath() + "\n" +
    886                                "The certificate was generated randomly, and is not associated with your " +
     898                               "The certificate was generated randomly.\n" +
     899                               "Unless you have changed the default settings, the certificate is not associated with your " +
    887900                               "IP address, host name, router identity, or destination keys.");
    888901        } else {
  • core/java/src/net/i2p/crypto/KeyStoreUtil.java

    r622c680 r79baf70  
    468468    public static boolean createKeys(File ks, String alias, String cname, String ou,
    469469                                     String keyPW) {
    470         return createKeys(ks, DEFAULT_KEYSTORE_PASSWORD, alias, cname, ou,
     470        return createKeys(ks, DEFAULT_KEYSTORE_PASSWORD, alias, cname, null, ou,
     471                          DEFAULT_KEY_VALID_DAYS, DEFAULT_KEY_ALGORITHM, DEFAULT_KEY_SIZE, keyPW);
     472    }
     473
     474    /**
     475     *  Create a keypair and store it in the keystore at ks, creating it if necessary.
     476     *  Use default keystore password, valid days, algorithm, and key size.
     477     *
     478     *  Warning, may take a long time.
     479     *
     480     *  @param ks path to the keystore
     481     *  @param alias the name of the key
     482     *  @param cname e.g. localhost. Must be a hostname or email address. IP addresses will not be correctly encoded.
     483     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     484     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     485     *  @param ou e.g. console
     486     *  @param keyPW the key password, must be at least 6 characters
     487     *
     488     *  @return success
     489     *  @since 0.9.34 added altNames param
     490     */
     491    public static boolean createKeys(File ks, String alias, String cname, Set<String> altNames, String ou,
     492                                     String keyPW) {
     493        return createKeys(ks, DEFAULT_KEYSTORE_PASSWORD, alias, cname, altNames, ou,
    471494                          DEFAULT_KEY_VALID_DAYS, DEFAULT_KEY_ALGORITHM, DEFAULT_KEY_SIZE, keyPW);
    472495    }
     
    495518    public static boolean createKeys(File ks, String ksPW, String alias, String cname, String ou,
    496519                                     int validDays, String keyAlg, int keySize, String keyPW) {
     520        return createKeys(ks, ksPW, alias, cname, null, ou, validDays, keyAlg, keySize, keyPW);
     521    }
     522
     523    /**
     524     *  Create a keypair and store it in the keystore at ks, creating it if necessary.
     525     *
     526     *  For new code, the createKeysAndCRL() with the SigType argument is recommended over this one,
     527     *  as it throws exceptions, and returns the certificate and CRL.
     528     *
     529     *  Warning, may take a long time.
     530     *
     531     *  @param ks path to the keystore
     532     *  @param ksPW the keystore password
     533     *  @param alias the name of the key
     534     *  @param cname e.g. localhost. Must be a hostname or email address. IP addresses will not be correctly encoded.
     535     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     536     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     537     *  @param ou e.g. console
     538     *  @param validDays e.g. 3652 (10 years)
     539     *  @param keyAlg e.g. DSA , RSA, EC
     540     *  @param keySize e.g. 1024
     541     *  @param keyPW the key password, must be at least 6 characters
     542     *
     543     *  @return success
     544     *  @since 0.9.34 added altNames param
     545     */
     546    public static boolean createKeys(File ks, String ksPW, String alias, String cname, Set<String> altNames, String ou,
     547                                     int validDays, String keyAlg, int keySize, String keyPW) {
    497548        boolean useKeytool = I2PAppContext.getGlobalContext().getBooleanProperty("crypto.useExternalKeytool");
    498549        if (useKeytool) {
     550            if (altNames != null)
     551                throw new IllegalArgumentException("can't do SAN in keytool");
    499552            return createKeysCLI(ks, ksPW, alias, cname, ou, validDays, keyAlg, keySize, keyPW);
    500553        } else {
    501554            try {
    502                 createKeysAndCRL(ks, ksPW, alias, cname, ou, validDays, keyAlg, keySize, keyPW);
     555                createKeysAndCRL(ks, ksPW, alias, cname, altNames, ou, validDays, keyAlg, keySize, keyPW);
    503556                return true;
    504557            } catch (GeneralSecurityException gse) {
     
    547600                                            int validDays, String keyAlg, int keySize, String keyPW)
    548601                                                throws GeneralSecurityException, IOException {
    549         String algoName = getSigAlg(keySize, keyAlg);
    550         SigType type = null;
    551         for (SigType t : EnumSet.allOf(SigType.class)) {
    552             if (t.getAlgorithmName().equals(algoName)) {
    553                 type = t;
    554                 break;
    555             }
    556         }
    557         if (type == null)
    558             throw new GeneralSecurityException("Unsupported algorithm/size: " + keyAlg + '/' + keySize);
    559         return createKeysAndCRL(ks, ksPW, alias, cname, ou, validDays, type, keyPW);
     602        return createKeysAndCRL(ks, ksPW, alias, cname, null, ou, validDays, keyAlg, keySize, keyPW);
    560603    }
    561604
     
    580623     *  @param alias the name of the key
    581624     *  @param cname e.g. localhost. Must be a hostname or email address. IP addresses will not be correctly encoded.
     625     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     626     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     627     *  @param ou e.g. console
     628     *  @param validDays e.g. 3652 (10 years)
     629     *  @param keyAlg e.g. DSA , RSA, EC
     630     *  @param keySize e.g. 1024
     631     *  @param keyPW the key password, must be at least 6 characters
     632     *  @return all you need:
     633     *      rv[0] is a Java PublicKey
     634     *      rv[1] is a Java PrivateKey
     635     *      rv[2] is a Java X509Certificate
     636     *      rv[3] is a Java X509CRL
     637     *  @since 0.9.34 added altNames param
     638     */
     639    public static Object[] createKeysAndCRL(File ks, String ksPW, String alias, String cname, Set<String> altNames, String ou,
     640                                            int validDays, String keyAlg, int keySize, String keyPW)
     641                                                throws GeneralSecurityException, IOException {
     642        String algoName = getSigAlg(keySize, keyAlg);
     643        SigType type = null;
     644        for (SigType t : EnumSet.allOf(SigType.class)) {
     645            if (t.getAlgorithmName().equals(algoName)) {
     646                type = t;
     647                break;
     648            }
     649        }
     650        if (type == null)
     651            throw new GeneralSecurityException("Unsupported algorithm/size: " + keyAlg + '/' + keySize);
     652        return createKeysAndCRL(ks, ksPW, alias, cname, altNames, ou, validDays, type, keyPW);
     653    }
     654
     655    /**
     656     *  New way - Native Java, does not call out to keytool.
     657     *  Create a keypair and store it in the keystore at ks, creating it if necessary.
     658     *
     659     *  This returns the public key, private key, certificate, and CRL in an array.
     660     *  All of these are Java classes. Keys may be converted to I2P classes with SigUtil.
     661     *  The private key and selfsigned cert are stored in the keystore.
     662     *  The public key may be derived from the private key with KeyGenerator.getSigningPublicKey().
     663     *  The public key certificate may be stored separately with
     664     *  CertUtil.saveCert() if desired.
     665     *  The CRL is not stored by this method, store it with
     666     *  CertUtil.saveCRL() or CertUtil.exportCRL() if desired.
     667     *
     668     *  Throws on all errors.
     669     *  Warning, may take a long time.
     670     *
     671     *  @param ks path to the keystore
     672     *  @param ksPW the keystore password
     673     *  @param alias the name of the key
     674     *  @param cname e.g. localhost. Must be a hostname or email address. IP addresses will not be correctly encoded.
    582675     *  @param ou e.g. console
    583676     *  @param validDays e.g. 3652 (10 years)
     
    591684     */
    592685    public static Object[] createKeysAndCRL(File ks, String ksPW, String alias, String cname, String ou,
     686                                            int validDays, SigType type, String keyPW)
     687                                                throws GeneralSecurityException, IOException {
     688        return createKeysAndCRL(ks, ksPW, alias, cname, null, ou, validDays, type, keyPW);
     689    }
     690
     691    /**
     692     *  New way - Native Java, does not call out to keytool.
     693     *  Create a keypair and store it in the keystore at ks, creating it if necessary.
     694     *
     695     *  This returns the public key, private key, certificate, and CRL in an array.
     696     *  All of these are Java classes. Keys may be converted to I2P classes with SigUtil.
     697     *  The private key and selfsigned cert are stored in the keystore.
     698     *  The public key may be derived from the private key with KeyGenerator.getSigningPublicKey().
     699     *  The public key certificate may be stored separately with
     700     *  CertUtil.saveCert() if desired.
     701     *  The CRL is not stored by this method, store it with
     702     *  CertUtil.saveCRL() or CertUtil.exportCRL() if desired.
     703     *
     704     *  Throws on all errors.
     705     *  Warning, may take a long time.
     706     *
     707     *  @param ks path to the keystore
     708     *  @param ksPW the keystore password
     709     *  @param alias the name of the key
     710     *  @param cname e.g. localhost. Must be a hostname or email address. IP addresses will not be correctly encoded.
     711     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     712     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     713     *  @param ou e.g. console
     714     *  @param validDays e.g. 3652 (10 years)
     715     *  @param keyPW the key password, must be at least 6 characters
     716     *  @return all you need:
     717     *      rv[0] is a Java PublicKey
     718     *      rv[1] is a Java PrivateKey
     719     *      rv[2] is a Java X509Certificate
     720     *      rv[3] is a Java X509CRL
     721     *  @since 0.9.34 added altNames param
     722     */
     723    public static Object[] createKeysAndCRL(File ks, String ksPW, String alias, String cname, Set<String> altNames, String ou,
    593724                                            int validDays, SigType type, String keyPW)
    594725                                                throws GeneralSecurityException, IOException {
     
    599730                throw new IOException("Can't create directory " + dir);
    600731        }
    601         Object[] rv = SelfSignedGenerator.generate(cname, ou, "I2P", "I2P Anonymous Network", null, null, validDays, type);
     732        Object[] rv = SelfSignedGenerator.generate(cname, altNames, ou, "I2P", "I2P Anonymous Network", null, null, validDays, type);
    602733        //PublicKey jpub = (PublicKey) rv[0];
    603734        PrivateKey jpriv = (PrivateKey) rv[1];
  • core/java/src/net/i2p/crypto/SelfSignedGenerator.java

    r622c680 r79baf70  
    1919import java.util.Date;
    2020import java.util.HashMap;
     21import java.util.HashSet;
    2122import java.util.List;
    2223import java.util.Map;
     24import java.util.Set;
    2325import java.util.TimeZone;
    2426
     
    2729import javax.crypto.spec.DHPublicKeySpec;
    2830import javax.security.auth.x500.X500Principal;
     31
     32import org.apache.http.conn.util.InetAddressUtils;
    2933
    3034import static net.i2p.crypto.SigUtil.intToASN1;
     
    3438import net.i2p.data.SigningPublicKey;
    3539import net.i2p.data.SimpleDataStructure;
     40import net.i2p.util.Addresses;
    3641import net.i2p.util.HexDump;
    3742import net.i2p.util.RandomSource;
     
    4348 *  storing in a Keystore with KeyStoreUtil.storePrivateKey().
    4449 *  All done programatically, no keytool, no BC libs, no sun classes.
    45  *  Ref: RFC 2459
     50 *  Ref: RFC 2459, RFC 5280
    4651 *
    47  *  This is coded to create a cert that is similar to what comes out of keytool,
    48  *  even if I don't understand all of it.
     52 *  This is coded to create a cert that is similar to what comes out of keytool.
     53 *
     54 *  NOTE: Recommended use is via KeyStoreUtil.createKeys() and related methods.
     55 *  This API may not be stable.
    4956 *
    5057 *  @since 0.9.25
     
    109116    public static Object[] generate(String cname, String ou, String o, String l, String st, String c,
    110117                             int validDays, SigType type) throws GeneralSecurityException {
     118        return generate(cname, null, ou, o, l, st, c, validDays, type);
     119    }
     120
     121    /**
     122     *  @param cname the common name, non-null. Must be a hostname or email address. IP addresses will not be correctly encoded.
     123     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     124     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     125     *  @param ou The OU (organizational unit) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     126     *  @param o The O (organization)in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     127     *  @param l The L (city or locality) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     128     *  @param st The ST (state or province) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     129     *  @param c The C (country) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     130     *
     131     *  @return length 4 array:
     132     *  rv[0] is a Java PublicKey
     133     *  rv[1] is a Java PrivateKey
     134     *  rv[2] is a Java X509Certificate
     135     *  rv[3] is a Java X509CRL
     136     *
     137     *  @since 0.9.34 added altNames param
     138     */
     139    public static Object[] generate(String cname, Set<String> altNames, String ou, String o, String l, String st, String c,
     140                             int validDays, SigType type) throws GeneralSecurityException {
    111141        SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(type);
    112142        SigningPublicKey pub = (SigningPublicKey) keys[0];
     
    133163        byte[] sigoid = getEncodedOIDSeq(oid);
    134164
    135         byte[] tbs = genTBS(cname, ou, o, l, st, c, validDays, sigoid, jpub);
     165        byte[] tbs = genTBS(cname, altNames, ou, o, l, st, c, validDays, sigoid, jpub);
    136166        int tbslen = tbs.length;
    137167
     
    262292    /**
    263293     *  @param cname the common name, non-null
     294     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     295     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
    264296     *  @param ou The OU (organizational unit) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
    265297     *  @param o The O (organization)in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     
    268300     *  @param c The C (country) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
    269301     */
    270     private static byte[] genTBS(String cname, String ou, String o, String l, String st, String c,
     302    private static byte[] genTBS(String cname, Set<String> altNames, String ou, String o, String l, String st, String c,
    271303                          int validDays, byte[] sigoid, PublicKey jpub) throws GeneralSecurityException {
    272304        // a0 ???, int = 2
     
    299331
    300332        byte[] pubbytes = jpub.getEncoded();
    301         byte[] extbytes = getExtensions(pubbytes, cname);
     333        byte[] extbytes = getExtensions(pubbytes, cname, altNames);
    302334
    303335        int len = version.length + serial.length + sigoid.length + issuer.length +
     
    495527     *
    496528     *  @param pubbytes bit string
     529     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     530     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
    497531     *  @return ASN.1 encoded object
    498532     */
    499     private static byte[] getExtensions(byte[] pubbytes, String cname) {
     533    private static byte[] getExtensions(byte[] pubbytes, String cname, Set<String> altNames) {
    500534        // RFC 2549 sec. 4.2.1.2
    501535        // subject public key identifier is the sha1 hash of the bit string of the public key
     
    531565        int ext3len = oid3.length + TRUE.length + spaceFor(wrap3len);
    532566
    533         // TODO if IP address, encode as 4 or 16 bytes
    534         byte[] cnameBytes = DataHelper.getASCII(cname);
    535         int wrap41len = spaceFor(cnameBytes.length);
    536         // only used for CA
    537         byte[] ipv4;
    538         byte[] ipv6;
     567        int wrap41len = 0;
     568        if (altNames == null)
     569            altNames = new HashSet<String>(4);
     570        else
     571            altNames.remove("0:0:0:0:0:0:0:1");  // We don't want dup of "::1"
     572        altNames.add(cname);
    539573        final boolean isCA = !cname.contains("@");
    540574        if (isCA) {
    541             ipv4 = new byte[] { 127, 0, 0, 1 };
    542             ipv6 = new byte[16];
    543             ipv6[15] = 1;
    544             wrap41len += spaceFor(ipv4.length) + spaceFor(ipv6.length);
    545         } else {
    546             ipv4 = null;
    547             ipv6 = null;
     575            altNames.add("localhost");
     576            altNames.add("127.0.0.1");
     577            altNames.add("::1");
     578        }
     579        for (String n : altNames) {
     580            int len;
     581            if (InetAddressUtils.isIPv4Address(n))
     582                len = 4;
     583            else if (InetAddressUtils.isIPv6Address(n))
     584                len = 16;
     585            else
     586                len = n.length();
     587            wrap41len += spaceFor(len);
    548588        }
    549589        int wrap4len = spaceFor(wrap41len);
     
    644684        System.arraycopy(oid4, 0, rv, idx, oid4.length);
    645685        idx += oid4.length;
    646         // octet string wraps a sequence containing a choice 2 (DNSName) IA5String
    647         // followed by two byteArrays (IP addresses)
     686        // octet string wraps a sequence containing the names and IP addresses
    648687        rv[idx++] = (byte) 0x04;
    649688        idx = intToASN1(rv, idx, wrap4len);
    650689        rv[idx++] = (byte) 0x30;
    651690        idx = intToASN1(rv, idx, wrap41len);
    652         // TODO if IP address, encode as 0x87
    653         rv[idx++] = (byte) (isCA ? 0x82 : 0x81); // choice, dNSName or rfc822Name, IA5String implied
    654         idx = intToASN1(rv, idx, cnameBytes.length);
    655         System.arraycopy(cnameBytes, 0, rv, idx, cnameBytes.length);
    656         idx += cnameBytes.length;
    657         if (isCA) {
    658             rv[idx++] = (byte) 0x87; // choice, octet string for IP address
    659             idx = intToASN1(rv, idx, ipv4.length);
    660             System.arraycopy(ipv4, 0, rv, idx, ipv4.length);
    661             idx += ipv4.length;
    662             rv[idx++] = (byte) 0x87; // choice, octet string for IP address
    663             idx = intToASN1(rv, idx, ipv6.length);
    664             System.arraycopy(ipv6, 0, rv, idx, ipv6.length);
    665             idx += ipv6.length;
     691        for (String n : altNames) {
     692            byte[] b;
     693            if (InetAddressUtils.isIPv4Address(n) ||
     694                InetAddressUtils.isIPv6Address(n)) {
     695                b = Addresses.getIP(n);
     696                if (b == null)  // shouldn't happen
     697                    throw new IllegalArgumentException("fail " + n);
     698                rv[idx++] = (byte) 0x87; // choice, octet string for IP address
     699            } else {
     700                b = DataHelper.getASCII(n);
     701                rv[idx++] = (byte) (isCA ? 0x82 : 0x81); // choice, dNSName or rfc822Name, IA5String implied
     702            }
     703            idx = intToASN1(rv, idx, b.length);
     704            System.arraycopy(b, 0, rv, idx, b.length);
     705            idx += b.length;
    666706        }
    667707
Note: See TracChangeset for help on using the changeset viewer.