1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18/** 19* @author Vladimir N. Molotkov 20* @version $Revision$ 21*/ 22 23package org.apache.harmony.security.utils; 24 25import java.security.Provider; 26import java.security.Security; 27import java.util.HashMap; 28import java.util.Map; 29import java.util.Set; 30import java.util.Map.Entry; 31 32import org.apache.harmony.security.Util; 33import org.apache.harmony.security.asn1.ObjectIdentifier; 34 35/** 36 * Provides Algorithm Name to OID and OID to Algorithm Name mappings. Some known 37 * mappings are hardcoded. Tries to obtain additional mappings from installed 38 * providers during initialization. 39 */ 40public class AlgNameMapper { 41 42 // Will search OID mappings for these services 43 private static final String[] serviceName = { 44 "Cipher", //$NON-NLS-1$ 45 "AlgorithmParameters", //$NON-NLS-1$ 46 "Signature" //$NON-NLS-1$ 47 }; 48 49 // These mappings CAN NOT be overridden 50 // by the ones from available providers 51 // during maps initialization 52 // (source: http://asn1.elibel.tm.fr): 53 private static final String[][] knownAlgMappings = { 54 {"1.2.840.10040.4.1", "DSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 55 {"1.2.840.10040.4.3", "SHA1withDSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 56 {"1.2.840.113549.1.1.1", "RSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 57 // BEGIN android-removed 58 // Dropping MD2 59 // {"1.2.840.113549.1.1.2", "MD2withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 60 // END android-removed 61 {"1.2.840.113549.1.1.4", "MD5withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 62 {"1.2.840.113549.1.1.5", "SHA1withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 63 {"1.2.840.113549.1.3.1", "DiffieHellman"}, //$NON-NLS-1$ //$NON-NLS-2$ 64 {"1.2.840.113549.1.5.3", "pbeWithMD5AndDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 65 {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 66 {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 67 {"1.2.840.113549.3.2", "RC2-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 68 {"1.2.840.113549.3.3", "RC2-EBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 69 {"1.2.840.113549.3.4", "RC4"}, //$NON-NLS-1$ //$NON-NLS-2$ 70 {"1.2.840.113549.3.5", "RC4WithMAC"}, //$NON-NLS-1$ //$NON-NLS-2$ 71 {"1.2.840.113549.3.6", "DESx-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 72 {"1.2.840.113549.3.7", "TripleDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 73 {"1.2.840.113549.3.8", "rc5CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 74 {"1.2.840.113549.3.9", "RC5-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$ 75 {"1.2.840.113549.3.10", "DESCDMF"}, //$NON-NLS-1$ //$NON-NLS-2$ 76 {"2.23.42.9.11.4.1", "ECDSA"}, //$NON-NLS-1$ //$NON-NLS-2$ 77 }; 78 // Maps alg name to OID 79 private static final Map<String, String> alg2OidMap = new HashMap<String, String>(); 80 // Maps OID to alg name 81 private static final Map<String, String> oid2AlgMap = new HashMap<String, String>(); 82 // Maps aliases to alg names 83 private static final Map<String, String> algAliasesMap = new HashMap<String, String>(); 84 85 static { 86 for (String[] element : knownAlgMappings) { 87 String algUC = Util.toUpperCase(element[1]); 88 alg2OidMap.put(algUC, element[0]); 89 oid2AlgMap.put(element[0], algUC); 90 // map upper case alg name to its original name 91 algAliasesMap.put(algUC, element[1]); 92 } 93 // 94 // Now search providers for mappings like 95 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 96 // or 97 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 98 // 99 Provider[] pl = Security.getProviders(); 100 for (Provider element : pl) { 101 selectEntries(element); 102 } 103 } 104 105 // No instances 106 private AlgNameMapper() { 107 } 108 109 /** 110 * Returns OID for algName 111 * 112 * @param algName algorithm name to be mapped 113 * @return OID as String 114 */ 115 public static String map2OID(String algName) { 116 // alg2OidMap map contains upper case keys 117 return alg2OidMap.get(Util.toUpperCase(algName)); 118 } 119 120 /** 121 * Returns algName for OID 122 * 123 * @param oid OID to be mapped 124 * @return algorithm name 125 */ 126 public static String map2AlgName(String oid) { 127 // oid2AlgMap map contains upper case values 128 String algUC = oid2AlgMap.get(oid); 129 // if not null there is always map UC->Orig 130 return algUC == null ? null : algAliasesMap.get(algUC); 131 } 132 133 /** 134 * Returns Algorithm name for given algorithm alias 135 * 136 * @param algName - alias 137 * @return algorithm name 138 */ 139 public static String getStandardName(String algName) { 140 return algAliasesMap.get(Util.toUpperCase(algName)); 141 } 142 143 // Searches given provider for mappings like 144 // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name> 145 // or 146 // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name> 147 // Puts mappings found into appropriate internal maps 148 private static void selectEntries(Provider p) { 149 Set<Map.Entry<Object, Object>> entrySet = p.entrySet(); 150 for (String service : serviceName) { 151 String keyPrfix2find = "Alg.Alias." + service + "."; //$NON-NLS-1$ //$NON-NLS-2$ 152 for (Entry<Object, Object> me : entrySet) { 153 String key = (String)me.getKey(); 154 if (key.startsWith(keyPrfix2find)) { 155 String alias = key.substring(keyPrfix2find.length()); 156 String alg = (String)me.getValue(); 157 String algUC = Util.toUpperCase(alg); 158 if (isOID(alias)) { 159 if (alias.startsWith("OID.")) { //$NON-NLS-1$ 160 alias = alias.substring(4); 161 } 162 // Do not overwrite already known mappings 163 boolean oid2AlgContains = oid2AlgMap.containsKey(alias); 164 boolean alg2OidContains = alg2OidMap.containsKey(algUC); 165 if (!oid2AlgContains || !alg2OidContains) { 166 if (!oid2AlgContains) { 167 oid2AlgMap.put(alias, algUC); 168 } 169 if (!alg2OidContains) { 170 alg2OidMap.put(algUC, alias); 171 } 172 // map upper case alg name to its original name 173 algAliasesMap.put(algUC, alg); 174 } 175 // Do not override known standard names 176 } else if (!algAliasesMap.containsKey(Util.toUpperCase(alias))) { 177 algAliasesMap.put(Util.toUpperCase(alias), alg); 178 } 179 } 180 } 181 } 182 } 183 184 /** 185 * Checks if parameter represents OID 186 * 187 * @param alias alias to be checked 188 * @return 'true' if parameter represents OID 189 */ 190 public static boolean isOID(String alias) { 191 // BEGIN android-changed 192 return ObjectIdentifier.isOID(normalize(alias)); 193 // END android-changed 194 } 195 196 /** 197 * Removes leading "OID." from oid String passed 198 * 199 * @param oid string that may contain leading "OID." 200 * @return string passed without leading "OID." 201 */ 202 public static String normalize(String oid) { 203 return oid.startsWith("OID.") //$NON-NLS-1$ 204 ? oid.substring(4) 205 : oid; 206 } 207 208 /** 209 * Present all internal maps as formatted string 210 * @return Internal maps String representation 211 */ 212 public static String dump() { 213 StringBuilder sb = new StringBuilder("alg2OidMap: "); //$NON-NLS-1$ 214 sb.append(alg2OidMap); 215 sb.append("\noid2AlgMap: "); //$NON-NLS-1$ 216 sb.append(oid2AlgMap); 217 sb.append("\nalgAliasesMap: "); //$NON-NLS-1$ 218 sb.append(algAliasesMap); 219 return sb.toString(); 220 } 221} 222