Home | History | Annotate | Download | only in utils
      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 
     23 package org.apache.harmony.security.utils;
     24 
     25 import java.security.Provider;
     26 import java.security.Security;
     27 import java.util.HashMap;
     28 import java.util.Locale;
     29 import java.util.Map;
     30 import java.util.Map.Entry;
     31 import java.util.Set;
     32 import org.apache.harmony.security.asn1.ObjectIdentifier;
     33 import org.apache.harmony.security.fortress.Services;
     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  */
     40 public class AlgNameMapper {
     41     private static AlgNameMapperSource source = null;
     42 
     43     private static volatile int cacheVersion = -1;
     44 
     45     // Will search OID mappings for these services
     46     private static final String[] serviceName = {
     47             "Cipher",
     48             "AlgorithmParameters",
     49             "Signature"
     50     };
     51 
     52     // These mappings CAN NOT be overridden
     53     // by the ones from available providers
     54     // during maps initialization
     55     // (source: http://asn1.elibel.tm.fr):
     56     private static final String[][] knownAlgMappings = {
     57         {"1.2.840.10040.4.1",       "DSA"},
     58         {"1.2.840.10040.4.3",       "SHA1withDSA"},
     59         {"1.2.840.113549.1.1.1",    "RSA"},
     60         // BEGIN android-removed
     61         // Dropping MD2
     62         // {"1.2.840.113549.1.1.2",    "MD2withRSA"},
     63         // END android-removed
     64         {"1.2.840.113549.1.1.4",    "MD5withRSA"},
     65         {"1.2.840.113549.1.1.5",    "SHA1withRSA"},
     66         {"1.2.840.113549.1.3.1",    "DiffieHellman"},
     67         {"1.2.840.113549.1.5.3",    "pbeWithMD5AndDES-CBC"},
     68         {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"},
     69         {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"},
     70         {"1.2.840.113549.3.2",      "RC2-CBC"},
     71         {"1.2.840.113549.3.3",      "RC2-EBC"},
     72         {"1.2.840.113549.3.4",      "RC4"},
     73         {"1.2.840.113549.3.5",      "RC4WithMAC"},
     74         {"1.2.840.113549.3.6",      "DESx-CBC"},
     75         {"1.2.840.113549.3.7",      "TripleDES-CBC"},
     76         {"1.2.840.113549.3.8",      "rc5CBC"},
     77         {"1.2.840.113549.3.9",      "RC5-CBC"},
     78         {"1.2.840.113549.3.10",     "DESCDMF"},
     79         {"2.23.42.9.11.4.1",        "ECDSA"},
     80     };
     81     // Maps alg name to OID
     82     private static final Map<String, String> alg2OidMap = new HashMap<String, String>();
     83     // Maps OID to alg name
     84     private static final Map<String, String> oid2AlgMap = new HashMap<String, String>();
     85     // Maps aliases to alg names
     86     private static final Map<String, String> algAliasesMap = new HashMap<String, String>();
     87 
     88     static {
     89         for (String[] element : knownAlgMappings) {
     90             String algUC = element[1].toUpperCase(Locale.US);
     91             alg2OidMap.put(algUC, element[0]);
     92             oid2AlgMap.put(element[0], algUC);
     93             // map upper case alg name to its original name
     94             algAliasesMap.put(algUC, element[1]);
     95         }
     96     }
     97 
     98     // No instances
     99     private AlgNameMapper() {
    100     }
    101 
    102     private static synchronized void checkCacheVersion() {
    103         int newCacheVersion = Services.getCacheVersion();
    104         if (newCacheVersion != cacheVersion) {
    105             //
    106             // Now search providers for mappings like
    107             // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
    108             //  or
    109             // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
    110             //
    111             Provider[] pl = Security.getProviders();
    112             for (Provider element : pl) {
    113                 selectEntries(element);
    114             }
    115             cacheVersion = newCacheVersion;
    116         }
    117     }
    118 
    119     /**
    120      * Returns OID for algName
    121      *
    122      * @param algName algorithm name to be mapped
    123      * @return OID as String
    124      */
    125     public static String map2OID(String algName) {
    126         checkCacheVersion();
    127 
    128         // alg2OidMap map contains upper case keys
    129         String result = alg2OidMap.get(algName.toUpperCase(Locale.US));
    130         if (result != null) {
    131             return result;
    132         }
    133 
    134         // Check our external source.
    135         AlgNameMapperSource s = source;
    136         if (s != null) {
    137             return s.mapNameToOid(algName);
    138         }
    139 
    140         return null;
    141     }
    142 
    143     /**
    144      * Returns algName for OID
    145      *
    146      * @param oid OID to be mapped
    147      * @return algorithm name
    148      */
    149     public static String map2AlgName(String oid) {
    150         checkCacheVersion();
    151 
    152         // oid2AlgMap map contains upper case values
    153         String algUC = oid2AlgMap.get(oid);
    154         // if not null there is always map UC->Orig
    155         if (algUC != null) {
    156             return algAliasesMap.get(algUC);
    157         }
    158 
    159         // Check our external source.
    160         AlgNameMapperSource s = source;
    161         if (s != null) {
    162             return s.mapOidToName(oid);
    163         }
    164 
    165         return null;
    166     }
    167 
    168     /**
    169      * Returns Algorithm name for given algorithm alias
    170      *
    171      * @param algName - alias
    172      * @return algorithm name
    173      */
    174     public static String getStandardName(String algName) {
    175         return algAliasesMap.get(algName.toUpperCase(Locale.US));
    176     }
    177 
    178     // Searches given provider for mappings like
    179     // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
    180     //  or
    181     // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
    182     // Puts mappings found into appropriate internal maps
    183     private static void selectEntries(Provider p) {
    184         Set<Map.Entry<Object, Object>> entrySet = p.entrySet();
    185         for (String service : serviceName) {
    186             String keyPrfix2find = "Alg.Alias." + service + ".";
    187             for (Entry<Object, Object> me : entrySet) {
    188                 String key = (String)me.getKey();
    189                 if (key.startsWith(keyPrfix2find)) {
    190                     String alias = key.substring(keyPrfix2find.length());
    191                     String alg = (String)me.getValue();
    192                     String algUC = alg.toUpperCase(Locale.US);
    193                     if (isOID(alias)) {
    194                         if (alias.startsWith("OID.")) {
    195                             alias = alias.substring(4);
    196                         }
    197                         // Do not overwrite already known mappings
    198                         boolean oid2AlgContains = oid2AlgMap.containsKey(alias);
    199                         boolean alg2OidContains = alg2OidMap.containsKey(algUC);
    200                         if (!oid2AlgContains || !alg2OidContains) {
    201                             if (!oid2AlgContains) {
    202                                 oid2AlgMap.put(alias, algUC);
    203                             }
    204                             if (!alg2OidContains) {
    205                                 alg2OidMap.put(algUC, alias);
    206                             }
    207                             // map upper case alg name to its original name
    208                             algAliasesMap.put(algUC, alg);
    209                         }
    210                            // Do not override known standard names
    211                     } else if (!algAliasesMap.containsKey(alias.toUpperCase(Locale.US))) {
    212                         algAliasesMap.put(alias.toUpperCase(Locale.US), alg);
    213                     }
    214                 }
    215             }
    216         }
    217     }
    218 
    219     /**
    220      * Checks if parameter represents OID
    221      *
    222      * @param alias alias to be checked
    223      * @return 'true' if parameter represents OID
    224      */
    225     public static boolean isOID(String alias) {
    226         return ObjectIdentifier.isOID(normalize(alias));
    227     }
    228 
    229     /**
    230      * Removes leading "OID." from oid String passed
    231      *
    232      * @param oid string that may contain leading "OID."
    233      * @return string passed without leading "OID."
    234      */
    235     public static String normalize(String oid) {
    236         return oid.startsWith("OID.")
    237             ? oid.substring(4)
    238             : oid;
    239     }
    240 
    241     public static void setSource(AlgNameMapperSource source) {
    242         AlgNameMapper.source = source;
    243     }
    244 }
    245