|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.x509; |
|
|
|
import java.io.*; |
|
import java.util.*; |
|
import java.util.concurrent.ConcurrentHashMap; |
|
import java.security.*; |
|
|
|
import sun.security.util.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class AlgorithmId implements Serializable, DerEncoder { |
|
|
|
|
|
@java.io.Serial |
|
private static final long serialVersionUID = 7205873507486557157L; |
|
|
|
|
|
|
|
*/ |
|
private ObjectIdentifier algid; |
|
|
|
|
|
@SuppressWarnings("serial") |
|
private AlgorithmParameters algParams; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected transient byte[] encodedParams; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
public AlgorithmId() { } |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmId(ObjectIdentifier oid) { |
|
algid = oid; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmId(ObjectIdentifier oid, AlgorithmParameters algparams) { |
|
algid = oid; |
|
this.algParams = algparams; |
|
if (algParams != null) { |
|
try { |
|
encodedParams = algParams.getEncoded(); |
|
} catch (IOException ioe) { |
|
// Ignore this at the moment. This exception can occur |
|
// if AlgorithmParameters was not initialized yet. Will |
|
// try to re-getEncoded() again later. |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public AlgorithmId(ObjectIdentifier oid, DerValue params) |
|
throws IOException { |
|
this.algid = oid; |
|
if (params != null) { |
|
encodedParams = params.toByteArray(); |
|
decodeParams(); |
|
} |
|
} |
|
|
|
protected void decodeParams() throws IOException { |
|
String algidName = getName(); |
|
try { |
|
algParams = AlgorithmParameters.getInstance(algidName); |
|
} catch (NoSuchAlgorithmException e) { |
|
|
|
|
|
|
|
*/ |
|
algParams = null; |
|
return; |
|
} |
|
|
|
|
|
algParams.init(encodedParams.clone()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public final void encode(DerOutputStream out) throws IOException { |
|
derEncode(out); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public void derEncode (OutputStream out) throws IOException { |
|
DerOutputStream bytes = new DerOutputStream(); |
|
DerOutputStream tmp = new DerOutputStream(); |
|
|
|
bytes.putOID(algid); |
|
|
|
|
|
if (algParams != null && encodedParams == null) { |
|
encodedParams = algParams.getEncoded(); |
|
// If still not initialized. Let the IOE be thrown. |
|
} |
|
|
|
if (encodedParams == null) { |
|
// Changes backed out for compatibility with Solaris |
|
|
|
// Several AlgorithmId should omit the whole parameter part when |
|
// it's NULL. They are --- |
|
// RFC 3370 2.1: Implementations SHOULD generate SHA-1 |
|
// AlgorithmIdentifiers with absent parameters. |
|
// RFC 3447 C1: When id-sha1, id-sha224, id-sha256, id-sha384 and |
|
// id-sha512 are used in an AlgorithmIdentifier the parameters |
|
// (which are optional) SHOULD be omitted. |
|
// RFC 3279 2.3.2: The id-dsa algorithm syntax includes optional |
|
// domain parameters... When omitted, the parameters component |
|
// MUST be omitted entirely |
|
// RFC 3370 3.1: When the id-dsa-with-sha1 algorithm identifier |
|
// is used, the AlgorithmIdentifier parameters field MUST be absent. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}*/ |
|
if (algid.equals(RSASSA_PSS_oid) || algid.equals(ed448_oid) |
|
|| algid.equals(ed25519_oid) |
|
|| algid.equals(x448_oid) |
|
|| algid.equals(x25519_oid) |
|
|| algid.equals(SHA224withECDSA_oid) |
|
|| algid.equals(SHA256withECDSA_oid) |
|
|| algid.equals(SHA384withECDSA_oid) |
|
|| algid.equals(SHA512withECDSA_oid)) { |
|
// RFC 4055 3.3: when an RSASSA-PSS key does not require |
|
// parameter validation, field is absent. |
|
// RFC 8410 3: for id-X25519, id-X448, id-Ed25519, and |
|
// id-Ed448, the parameters must be absent. |
|
// RFC 5758 3.2: the encoding must omit the parameters field |
|
// for ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384 |
|
// and ecdsa-with-SHA512. |
|
} else { |
|
bytes.putNull(); |
|
} |
|
} else { |
|
bytes.write(encodedParams); |
|
} |
|
tmp.write(DerValue.tag_Sequence, bytes); |
|
out.write(tmp.toByteArray()); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final byte[] encode() throws IOException { |
|
DerOutputStream out = new DerOutputStream(); |
|
derEncode(out); |
|
return out.toByteArray(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final ObjectIdentifier getOID () { |
|
return algid; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String getName() { |
|
String oidStr = algid.toString(); |
|
|
|
KnownOIDs o = KnownOIDs.findMatch(oidStr); |
|
if (o == KnownOIDs.SpecifiedSHA2withECDSA) { |
|
if (encodedParams != null) { |
|
try { |
|
AlgorithmId digestParams = |
|
AlgorithmId.parse(new DerValue(encodedParams)); |
|
String digestAlg = digestParams.getName(); |
|
return digestAlg.replace("-", "") + "withECDSA"; |
|
} catch (IOException e) { |
|
// ignore |
|
} |
|
} |
|
} |
|
if (o != null) { |
|
return o.stdName(); |
|
} else { |
|
String n = aliasOidsTable().get(oidStr); |
|
if (n != null) { |
|
return n; |
|
} else { |
|
return algid.toString(); |
|
} |
|
} |
|
} |
|
|
|
public AlgorithmParameters getParameters() { |
|
return algParams; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public byte[] getEncodedParams() throws IOException { |
|
return (encodedParams == null || |
|
algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value())) |
|
? null |
|
: encodedParams.clone(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean equals(AlgorithmId other) { |
|
return algid.equals((Object)other.algid) && |
|
Arrays.equals(encodedParams, other.encodedParams); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean equals(Object other) { |
|
if (this == other) { |
|
return true; |
|
} |
|
if (other instanceof AlgorithmId) { |
|
return equals((AlgorithmId) other); |
|
} else if (other instanceof ObjectIdentifier) { |
|
return equals((ObjectIdentifier) other); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public final boolean equals(ObjectIdentifier id) { |
|
return algid.equals((Object)id); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public int hashCode() { |
|
int hashCode = algid.hashCode(); |
|
hashCode = 31 * hashCode + Arrays.hashCode(encodedParams); |
|
return hashCode; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected String paramsToString() { |
|
if (encodedParams == null) { |
|
return ""; |
|
} else if (algParams != null) { |
|
return ", " + algParams.toString(); |
|
} else { |
|
return ", params unparsed"; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public String toString() { |
|
return getName() + paramsToString(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static AlgorithmId parse(DerValue val) throws IOException { |
|
if (val.tag != DerValue.tag_Sequence) { |
|
throw new IOException("algid parse error, not a sequence"); |
|
} |
|
|
|
|
|
|
|
*/ |
|
ObjectIdentifier algid; |
|
DerValue params; |
|
DerInputStream in = val.toDerInputStream(); |
|
|
|
algid = in.getOID(); |
|
if (in.available() == 0) { |
|
params = null; |
|
} else { |
|
params = in.getDerValue(); |
|
if (params.tag == DerValue.tag_Null) { |
|
if (params.length() != 0) { |
|
throw new IOException("invalid NULL"); |
|
} |
|
params = null; |
|
} |
|
if (in.available() != 0) { |
|
throw new IOException("Invalid AlgorithmIdentifier: extra data"); |
|
} |
|
} |
|
|
|
return new AlgorithmId(algid, params); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Deprecated |
|
public static AlgorithmId getAlgorithmId(String algname) |
|
throws NoSuchAlgorithmException { |
|
return get(algname); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static AlgorithmId get(String algname) |
|
throws NoSuchAlgorithmException { |
|
ObjectIdentifier oid; |
|
try { |
|
oid = algOID(algname); |
|
} catch (IOException ioe) { |
|
throw new NoSuchAlgorithmException |
|
("Invalid ObjectIdentifier " + algname); |
|
} |
|
|
|
if (oid == null) { |
|
throw new NoSuchAlgorithmException |
|
("unrecognized algorithm name: " + algname); |
|
} |
|
return new AlgorithmId(oid); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static AlgorithmId get(AlgorithmParameters algparams) |
|
throws NoSuchAlgorithmException { |
|
ObjectIdentifier oid; |
|
String algname = algparams.getAlgorithm(); |
|
try { |
|
oid = algOID(algname); |
|
} catch (IOException ioe) { |
|
throw new NoSuchAlgorithmException |
|
("Invalid ObjectIdentifier " + algname); |
|
} |
|
if (oid == null) { |
|
throw new NoSuchAlgorithmException |
|
("unrecognized algorithm name: " + algname); |
|
} |
|
return new AlgorithmId(oid, algparams); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static ObjectIdentifier algOID(String name) throws IOException { |
|
if (name.startsWith("OID.")) { |
|
name = name.substring("OID.".length()); |
|
} |
|
|
|
KnownOIDs k = KnownOIDs.findMatch(name); |
|
if (k != null) { |
|
return ObjectIdentifier.of(k); |
|
} |
|
|
|
|
|
if (name.indexOf(".") == -1) { |
|
// see if there is a matching oid string alias mapping from |
|
|
|
name = name.toUpperCase(Locale.ENGLISH); |
|
String oidStr = aliasOidsTable().get(name); |
|
if (oidStr != null) { |
|
return ObjectIdentifier.of(oidStr); |
|
} return null; |
|
} else { |
|
return ObjectIdentifier.of(name); |
|
} |
|
} |
|
|
|
|
|
private static volatile Map<String,String> aliasOidsTable; |
|
|
|
|
|
public static void clearAliasOidsTable() { |
|
aliasOidsTable = null; |
|
} |
|
|
|
|
|
private static Map<String,String> aliasOidsTable() { |
|
|
|
Map<String,String> tab = aliasOidsTable; |
|
if (tab == null) { |
|
synchronized (AlgorithmId.class) { |
|
if ((tab = aliasOidsTable) == null) { |
|
aliasOidsTable = tab = collectOIDAliases(); |
|
} |
|
} |
|
} |
|
return tab; |
|
} |
|
|
|
private static boolean isKnownProvider(Provider p) { |
|
String pn = p.getName(); |
|
String mn = p.getClass().getModule().getName(); |
|
if (pn != null && mn != null) { |
|
return ((mn.equals("java.base") && |
|
(pn.equals("SUN") || pn.equals("SunRsaSign") || |
|
pn.equals("SunJCE") || pn.equals("SunJSSE"))) || |
|
(mn.equals("jdk.crypto.ec") && pn.equals("SunEC")) || |
|
(mn.equals("jdk.crypto.mscapi") && pn.equals("SunMSCAPI")) || |
|
(mn.equals("jdk.crypto.cryptoki") && |
|
pn.startsWith("SunPKCS11"))); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
private static ConcurrentHashMap<String, String> collectOIDAliases() { |
|
ConcurrentHashMap<String, String> t = new ConcurrentHashMap<>(); |
|
for (Provider provider : Security.getProviders()) { |
|
// skip providers which are already using SecurityProviderConstants |
|
|
|
if (isKnownProvider(provider)) { |
|
continue; |
|
} |
|
for (Object key : provider.keySet()) { |
|
String alias = (String)key; |
|
String upperCaseAlias = alias.toUpperCase(Locale.ENGLISH); |
|
int index; |
|
if (upperCaseAlias.startsWith("ALG.ALIAS") && |
|
(index = upperCaseAlias.indexOf("OID.", 0)) != -1) { |
|
index += "OID.".length(); |
|
if (index == alias.length()) { |
|
|
|
break; |
|
} |
|
String ostr = alias.substring(index); |
|
String stdAlgName = provider.getProperty(alias); |
|
if (stdAlgName != null) { |
|
stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH); |
|
} |
|
|
|
if (KnownOIDs.findMatch(stdAlgName) == null) { |
|
|
|
t.putIfAbsent(stdAlgName, ostr); |
|
} |
|
if (KnownOIDs.findMatch(ostr) == null) { |
|
|
|
t.putIfAbsent(ostr, stdAlgName); |
|
} |
|
} |
|
} |
|
} |
|
return t; |
|
} |
|
|
|
public static final ObjectIdentifier MD2_oid = |
|
ObjectIdentifier.of(KnownOIDs.MD2); |
|
|
|
public static final ObjectIdentifier MD5_oid = |
|
ObjectIdentifier.of(KnownOIDs.MD5); |
|
|
|
public static final ObjectIdentifier SHA_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_1); |
|
|
|
public static final ObjectIdentifier SHA224_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_224); |
|
|
|
public static final ObjectIdentifier SHA256_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_256); |
|
|
|
public static final ObjectIdentifier SHA384_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_384); |
|
|
|
public static final ObjectIdentifier SHA512_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_512); |
|
|
|
public static final ObjectIdentifier SHA512_224_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_512$224); |
|
|
|
public static final ObjectIdentifier SHA512_256_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA_512$256); |
|
|
|
public static final ObjectIdentifier SHA3_224_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA3_224); |
|
|
|
public static final ObjectIdentifier SHA3_256_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA3_256); |
|
|
|
public static final ObjectIdentifier SHA3_384_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA3_384); |
|
|
|
public static final ObjectIdentifier SHA3_512_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA3_512); |
|
|
|
public static final ObjectIdentifier DSA_oid = |
|
ObjectIdentifier.of(KnownOIDs.DSA); |
|
|
|
public static final ObjectIdentifier EC_oid = |
|
ObjectIdentifier.of(KnownOIDs.EC); |
|
|
|
public static final ObjectIdentifier RSAEncryption_oid = |
|
ObjectIdentifier.of(KnownOIDs.RSA); |
|
|
|
public static final ObjectIdentifier RSASSA_PSS_oid = |
|
ObjectIdentifier.of(KnownOIDs.RSASSA_PSS); |
|
|
|
public static final ObjectIdentifier MGF1_oid = |
|
ObjectIdentifier.of(KnownOIDs.MGF1); |
|
|
|
public static final ObjectIdentifier ed25519_oid = |
|
ObjectIdentifier.of(KnownOIDs.Ed25519); |
|
public static final ObjectIdentifier ed448_oid = |
|
ObjectIdentifier.of(KnownOIDs.Ed448); |
|
|
|
public static final ObjectIdentifier x25519_oid = |
|
ObjectIdentifier.of(KnownOIDs.X25519); |
|
public static final ObjectIdentifier x448_oid = |
|
ObjectIdentifier.of(KnownOIDs.X448); |
|
|
|
public static final ObjectIdentifier SHA224withECDSA_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA224withECDSA); |
|
public static final ObjectIdentifier SHA256withECDSA_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA256withECDSA); |
|
public static final ObjectIdentifier SHA384withECDSA_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA384withECDSA); |
|
public static final ObjectIdentifier SHA512withECDSA_oid = |
|
ObjectIdentifier.of(KnownOIDs.SHA512withECDSA); |
|
} |