blob: 8df02c9a62c6ba88e174b70d350b14ddd4a96ed4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Vladimir N. Molotkov
* @version $Revision$
*/
package org.apache.harmony.security.utils;
import java.security.Provider;
import java.security.Security;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.harmony.security.asn1.ObjectIdentifier;
import org.apache.harmony.security.fortress.Services;
/**
* Provides Algorithm Name to OID and OID to Algorithm Name mappings. Some known
* mappings are hardcoded. Tries to obtain additional mappings from installed
* providers during initialization.
*/
public class AlgNameMapper {
private static AlgNameMapperSource source = null;
private static volatile int cacheVersion = -1;
// Will search OID mappings for these services
private static final String[] serviceName = {
"Cipher",
"AlgorithmParameters",
"Signature"
};
// These mappings CAN NOT be overridden
// by the ones from available providers
// during maps initialization
// (source: http://asn1.elibel.tm.fr):
private static final String[][] knownAlgMappings = {
{"1.2.840.10040.4.1", "DSA"},
{"1.2.840.10040.4.3", "SHA1withDSA"},
{"1.2.840.113549.1.1.1", "RSA"},
// BEGIN android-removed
// Dropping MD2
// {"1.2.840.113549.1.1.2", "MD2withRSA"},
// END android-removed
{"1.2.840.113549.1.1.4", "MD5withRSA"},
{"1.2.840.113549.1.1.5", "SHA1withRSA"},
{"1.2.840.113549.1.3.1", "DiffieHellman"},
{"1.2.840.113549.1.5.3", "pbeWithMD5AndDES-CBC"},
{"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"},
{"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"},
{"1.2.840.113549.3.2", "RC2-CBC"},
{"1.2.840.113549.3.3", "RC2-EBC"},
{"1.2.840.113549.3.4", "RC4"},
{"1.2.840.113549.3.5", "RC4WithMAC"},
{"1.2.840.113549.3.6", "DESx-CBC"},
{"1.2.840.113549.3.7", "TripleDES-CBC"},
{"1.2.840.113549.3.8", "rc5CBC"},
{"1.2.840.113549.3.9", "RC5-CBC"},
{"1.2.840.113549.3.10", "DESCDMF"},
{"2.23.42.9.11.4.1", "ECDSA"},
};
// Maps alg name to OID
private static final Map<String, String> alg2OidMap = new HashMap<String, String>();
// Maps OID to alg name
private static final Map<String, String> oid2AlgMap = new HashMap<String, String>();
// Maps aliases to alg names
private static final Map<String, String> algAliasesMap = new HashMap<String, String>();
static {
for (String[] element : knownAlgMappings) {
addMapping(element[0], element[1]);
}
}
/**
* Adds a mapping to the internal table. Will overwrite any entry already
* present. Visible for testing.
*/
public static void addMapping(String oid, String name) {
String nameUC = name.toUpperCase(Locale.ROOT);
alg2OidMap.put(nameUC, oid);
oid2AlgMap.put(oid, nameUC);
// map upper case alg name to its original name
algAliasesMap.put(nameUC, name);
}
/**
* Removes a mapping from the internal table. Visible for testing.
*/
public static void removeMapping(String oid, String name) {
String nameUC = name.toUpperCase(Locale.ROOT);
alg2OidMap.remove(nameUC);
oid2AlgMap.remove(oid);
// map upper case alg name to its original name
algAliasesMap.remove(nameUC);
}
// No instances
private AlgNameMapper() {
}
private static synchronized void checkCacheVersion() {
int newCacheVersion = Services.getCacheVersion();
if (newCacheVersion != cacheVersion) {
//
// Now search providers for mappings like
// Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
// or
// Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
//
Provider[] pl = Security.getProviders();
for (Provider element : pl) {
selectEntries(element);
}
cacheVersion = newCacheVersion;
}
}
/**
* Returns OID for algName
*
* @param algName algorithm name to be mapped
* @return OID as String
*/
public static String map2OID(String algName) {
checkCacheVersion();
// alg2OidMap map contains upper case keys
String result = alg2OidMap.get(algName.toUpperCase(Locale.ROOT));
if (result != null) {
return result;
}
// Check our external source.
AlgNameMapperSource s = source;
if (s != null) {
return s.mapNameToOid(algName);
}
return null;
}
/**
* Returns algName for OID
*
* @param oid OID to be mapped
* @return algorithm name or {@code null} if not found.
*/
public static String map2AlgName(String oid) {
checkCacheVersion();
// oid2AlgMap map contains upper case values
String algUC = oid2AlgMap.get(oid);
// if not null there is always map UC->Orig
if (algUC != null) {
return algAliasesMap.get(algUC);
}
// Check our external source.
AlgNameMapperSource s = source;
if (s != null) {
return s.mapOidToName(oid);
}
return null;
}
/**
* Returns Algorithm name for given algorithm alias
*
* @param algName - alias
* @return algorithm name
*/
public static String getStandardName(String algName) {
return algAliasesMap.get(algName.toUpperCase(Locale.ROOT));
}
// Searches given provider for mappings like
// Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
// or
// Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
// Puts mappings found into appropriate internal maps
private static void selectEntries(Provider p) {
Set<Map.Entry<Object, Object>> entrySet = p.entrySet();
for (String service : serviceName) {
String keyPrfix2find = "Alg.Alias." + service + ".";
for (Entry<Object, Object> me : entrySet) {
String key = (String) me.getKey();
if (key.startsWith(keyPrfix2find)) {
String alias = key.substring(keyPrfix2find.length());
String alg = (String) me.getValue();
String algUC = alg.toUpperCase(Locale.ROOT);
if (isOID(alias)) {
if (alias.startsWith("OID.")) {
alias = alias.substring(4);
}
// Do not overwrite already known mappings
boolean oid2AlgContains = oid2AlgMap.containsKey(alias);
boolean alg2OidContains = alg2OidMap.containsKey(algUC);
if (!oid2AlgContains || !alg2OidContains) {
if (!oid2AlgContains) {
oid2AlgMap.put(alias, algUC);
}
if (!alg2OidContains) {
alg2OidMap.put(algUC, alias);
}
// map upper case alg name to its original name
algAliasesMap.put(algUC, alg);
}
// Do not override known standard names
} else if (!algAliasesMap.containsKey(alias.toUpperCase(Locale.ROOT))) {
algAliasesMap.put(alias.toUpperCase(Locale.ROOT), alg);
}
}
}
}
}
/**
* Checks if parameter represents OID
*
* @param alias alias to be checked
* @return 'true' if parameter represents OID
*/
public static boolean isOID(String alias) {
return ObjectIdentifier.isOID(normalize(alias));
}
/**
* Removes leading "OID." from oid String passed
*
* @param oid string that may contain leading "OID."
* @return string passed without leading "OID."
*/
public static String normalize(String oid) {
return oid.startsWith("OID.")
? oid.substring(4)
: oid;
}
public static void setSource(AlgNameMapperSource source) {
AlgNameMapper.source = source;
}
}