1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.oracle.security.ucrypto;
  27 
  28 import java.io.IOException;
  29 import java.util.HashMap;
  30 import java.util.StringTokenizer;
  31 import java.security.*;
  32 import sun.security.action.PutAllAction;
  33 import sun.security.action.GetPropertyAction;
  34 
  35 /**
  36  * OracleUcrypto provider main class.
  37  *
  38  * @since 1.9
  39  */
  40 public final class UcryptoProvider extends Provider {
  41 
  42     private static final long serialVersionUID = 351251234302833L;
  43 
  44     private static boolean DEBUG;
  45     private static HashMap<String, String> provProp;
  46 
  47     static {
  48         try {
  49             DEBUG = Boolean.parseBoolean(AccessController.doPrivileged
  50                 (new GetPropertyAction("com.oracle.security.ucrypto.debug")));
  51 
  52             // cannot use LoadLibraryAction because that would make the native
  53             // library available to the bootclassloader, but we run in the
  54             // extension classloader.
  55             provProp = AccessController.doPrivileged
  56                 (new PrivilegedAction<HashMap<String, String>>() {
  57                     public HashMap<String, String> run() {
  58                         try {
  59                             System.loadLibrary("j2ucrypto");
  60                             String osname = System.getProperty("os.name");
  61                             if (osname.startsWith("SunOS")) {
  62                                 return new HashMap<String, String>();
  63                             } else return null;
  64                         } catch (Error err) {
  65                             return null;
  66                         } catch (SecurityException se) {
  67                             return null;
  68                         }
  69                     }
  70                 });
  71             if (provProp != null) {
  72                 boolean[] result = loadLibraries();
  73                 if (result.length == 2) {
  74                     if (result[0]) { // successfully loaded libmd
  75                         provProp.put("MessageDigest.MD5",
  76                                      "com.oracle.security.ucrypto.NativeDigest$MD5");
  77                         provProp.put("MessageDigest.SHA",
  78                                      "com.oracle.security.ucrypto.NativeDigest$SHA1");
  79                         provProp.put("Alg.Alias.MessageDigest.SHA-1", "SHA");
  80                         provProp.put("Alg.Alias.MessageDigest.SHA1", "SHA");
  81                         provProp.put("MessageDigest.SHA-256",
  82                                      "com.oracle.security.ucrypto.NativeDigest$SHA256");
  83                         provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.1", "SHA-256");
  84                         provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.1", "SHA-256");
  85 
  86                         provProp.put("MessageDigest.SHA-384",
  87                                      "com.oracle.security.ucrypto.NativeDigest$SHA384");
  88                         provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.2", "SHA-384");
  89                         provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.2", "SHA-384");
  90 
  91                         provProp.put("MessageDigest.SHA-512",
  92                                      "com.oracle.security.ucrypto.NativeDigest$SHA512");
  93                         provProp.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
  94                         provProp.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3", "SHA-512");
  95 
  96                     }
  97                     if (result[1]) { // successfully loaded libsoftcrypto
  98                         String supportedMechs = getMechList();
  99                         debug("Prov: supported mechs = " + supportedMechs);
 100                         for (UcryptoMech m : UcryptoMech.values()) {
 101                             if (supportedMechs.indexOf(m.name() + ",") != -1) {
 102                                 String[] jceProps = m.jceProperties();
 103                                 // skip unsupported UcryptoMech
 104                                 if (jceProps == null) continue;
 105                                 for (int p = 0; p < jceProps.length; p++) {
 106                                     StringTokenizer st =
 107                                         new StringTokenizer(jceProps[p], ";");
 108                                     if (st.countTokens() != 2) {
 109                                         throw new RuntimeException("Wrong format: " + jceProps[p]);
 110                                     }
 111                                     provProp.put(st.nextToken(), st.nextToken());
 112                                 }
 113                             }
 114                         }
 115                         // NOTE: GCM support is only available since jdk 7
 116                         provProp.put("AlgorithmParameters.GCM",
 117                                      "com.oracle.security.ucrypto.GCMParameters");
 118                     }
 119                 } else {
 120                     debug("Prov: unexpected ucrypto library loading error, got " + result.length);
 121                 }
 122             }
 123         } catch (AccessControlException ace) {
 124             // disable Ucrypto provider
 125             DEBUG = false;
 126             provProp = null;
 127         }
 128     }
 129 
 130     static Provider provider = null;
 131     private static native boolean[] loadLibraries();
 132     private static native String getMechList();
 133 
 134     static void debug(String msg) {
 135         if (DEBUG) {
 136             System.out.println("UCrypto/" + msg);
 137         }
 138     }
 139 
 140     public UcryptoProvider() {
 141         super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
 142         if (provProp != null) {
 143             AccessController.doPrivileged(new PutAllAction(this, provProp));
 144         }
 145         if (provider == null) provider = this;
 146     }
 147 
 148     public UcryptoProvider(String configName) {
 149         super("OracleUcrypto", 1.9d, "Provider using Oracle Ucrypto API");
 150         try {
 151             if (provProp != null) {
 152                 HashMap<String, String> customProvProp =
 153                     new HashMap<String, String>(provProp);
 154                 Config c = new Config(configName);
 155                 String[] disabledServices = c.getDisabledServices();
 156                 for (int i = 0; i < disabledServices.length; i++) {
 157                     if (customProvProp.remove(disabledServices[i]) != null) {
 158                         debug("Prov: remove config-disabled service " + disabledServices[i]);
 159                     } else {
 160                         debug("Prov: ignore unsupported config-disabled service " +
 161                               disabledServices[i]);
 162                     }
 163                 }
 164                 AccessController.doPrivileged(new PutAllAction(this, customProvProp));
 165             }
 166         } catch (IOException ioe) { // thrown by Config
 167             throw new UcryptoException("Error parsing Config", ioe);
 168         }
 169         if (provider == null) provider = this;
 170     }
 171 
 172     public boolean equals(Object obj) {
 173         return this == obj;
 174     }
 175 
 176     public int hashCode() {
 177         return System.identityHashCode(this);
 178     }
 179 }