This is an automated email from the ASF dual-hosted git repository. shaojunwang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-java-tee-sdk.git
commit 263a6776cb14cabfd518e33748c796a55f314ae4 Author: cengfeng.lzy <[email protected]> AuthorDate: Thu Apr 7 11:33:14 2022 +0800 [Enc] Provide C only libenc_sunec.a on demand Summary: The library libsunec.a provided by Graal VM has C++ symbols which are not supported by OE SDK. So we compile a C symbol only libenc_sunec.a library for Enclave usages on demand. Test Plan: all tests pass Reviewers: lei.yul, jeffery.wsj, sanhong.lsh Issue: https://aone.alibaba-inc.com/task/41832504 CR: https://code.aone.alibaba-inc.com/java-tee/JavaEnclave/codereview/8856699 --- build.sh | 5 +- sdk/enclave/pom.xml | 8 +- .../enclave/NativeCommandUtil.java | 49 ++ .../enclave/SUNECReplaceFeature.java | 175 +++++++ .../enclave/substitutes/NativeSunECMethods.java | 21 + .../enclave/substitutes/SUNECSubstitutions.java | 53 ++ .../src/main/resources/native/sunec/ECC_JNI.c | 524 ++++++++++++++++++++ ...puting_enclave_substitutes_NativeSunECMethods.h | 53 ++ .../src/main/resources/native/sunec/ecc_impl.h | 271 +++++++++++ .../src/main/resources/native/sunec/ecl-exp.h | 201 ++++++++ .../src/main/resources/native/sunec/jlong.h | 31 ++ .../src/main/resources/native/sunec/jlong_md.h | 100 ++++ .../src/main/resources/native/sunec/jni_util.h | 534 +++++++++++++++++++++ .../enclave/NativeImageTest.java | 50 +- .../enclave/ReplaceSunECTest.java | 78 +++ .../enclave/testservice/EncryptionService.java | 10 + .../enclave/testservice/SunECOperations.java | 12 + ...computing.enclave.testservice.EncryptionService | 1 + tools/cicd/make.sh | 2 +- 19 files changed, 2131 insertions(+), 47 deletions(-) diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 index bed423b..44288a0 --- a/build.sh +++ b/build.sh @@ -7,11 +7,12 @@ cd "${SHELL_FOLDER}" # workspace dir is the same as build.sh path location. WORKDIR="$PWD" +SETTING="--settings /root/tools/settings.xml" # Build JavaEnclave SDK -cd "${WORKDIR}"/sdk && mvn --settings /root/tools/settings.xml clean install +cd "${WORKDIR}"/sdk && mvn $SETTING clean install # Install JavaEnclave SDK rm -rf /opt/javaenclave && mkdir -p /opt/javaenclave && cp -r ${SHELL_FOLDER}/sdk/native/bin /opt/javaenclave \ && cp -r ${SHELL_FOLDER}/sdk/native/config /opt/javaenclave && cp -r ${SHELL_FOLDER}/sdk/native/script/build_app /opt/javaenclave # Test unit test cases in JavaEnclave -cd "${WORKDIR}"/test && mvn -X --settings /root/tools/settings.xml -Pnative -e clean package +cd "${WORKDIR}"/test && mvn -X $SETTING -Pnative -e clean package diff --git a/sdk/enclave/pom.xml b/sdk/enclave/pom.xml index e586e83..3875579 100644 --- a/sdk/enclave/pom.xml +++ b/sdk/enclave/pom.xml @@ -96,7 +96,7 @@ <target>11</target> <compilerArgs> <arg>--add-modules</arg> - <arg>jdk.internal.vm.ci,jdk.internal.vm.compiler</arg> + <arg>jdk.internal.vm.ci,jdk.internal.vm.compiler,jdk.crypto.ec</arg> <arg>--add-exports</arg> <arg>jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED</arg> <arg>--add-exports</arg> @@ -105,6 +105,8 @@ <arg>jdk.internal.vm.compiler/org.graalvm.compiler.options=ALL-UNNAMED</arg> <arg>--add-exports</arg> <arg>jdk.internal.vm.compiler/org.graalvm.compiler.word=ALL-UNNAMED</arg> + <arg>--add-exports</arg> + <arg>jdk.crypto.ec/sun.security.ec=ALL-UNNAMED</arg> </compilerArgs> <!--OptionProcessor can automatically generate OptionDescriptor classes at javac time--> <annotationProcessorPaths> @@ -143,7 +145,7 @@ <doclint>none</doclint> <additionalJOptions> <additionalJOption>--add-modules</additionalJOption> - <additionalJOption>jdk.internal.vm.ci,jdk.internal.vm.compiler</additionalJOption> + <additionalJOption>jdk.internal.vm.ci,jdk.internal.vm.compiler,jdk.crypto.ec</additionalJOption> <additionalJOption>--add-exports</additionalJOption> <additionalJOption>jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED</additionalJOption> <additionalJOption>--add-exports</additionalJOption> @@ -152,6 +154,8 @@ <additionalJOption>jdk.internal.vm.compiler/org.graalvm.compiler.options=ALL-UNNAMED</additionalJOption> <additionalJOption>--add-exports</additionalJOption> <additionalJOption>jdk.internal.vm.compiler/org.graalvm.compiler.word=ALL-UNNAMED</additionalJOption> + <additionalJOption>--add-exports</additionalJOption> + <additionalJOption>jdk.crypto.ec/sun.security.ec=ALL-UNNAMED</additionalJOption> </additionalJOptions> </configuration> <version>3.2.0</version> diff --git a/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/NativeCommandUtil.java b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/NativeCommandUtil.java new file mode 100644 index 0000000..9966a30 --- /dev/null +++ b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/NativeCommandUtil.java @@ -0,0 +1,49 @@ +package com.alibaba.confidentialcomputing.enclave; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.SequenceInputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +public class NativeCommandUtil { + public static final Path GRAALVM_HOME = Paths.get(System.getenv("GRAALVM_HOME")); + + public static int executeNewProcess(List<String> command, Path workDir) { + if (command == null || command.isEmpty()) { + throw new RuntimeException("Didn't provide any execution command."); + } + ProcessBuilder pb = new ProcessBuilder(command).directory(workDir.toFile()); + pb.redirectErrorStream(true); + String oneLineCommand = command.stream().collect(Collectors.joining(" ")); + System.out.println(oneLineCommand); + Process p = null; + try { + p = pb.start(); + InputStreamReader inst = new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8); + try (BufferedReader br = new BufferedReader(inst)) { + String res; + while ((res = br.readLine()) != null) { + System.out.println(res); + } + } + int exitCode = p.waitFor(); + if (exitCode != 0) { + throw new RuntimeException("Failed to execute command:\n " + oneLineCommand + + "\n Working directory is :" + workDir.toString() + "\n The exit code is " + exitCode+ + "\n"); + } + return 0; + } catch (IOException | InterruptedException e) { + throw new RuntimeException("Failed to execute command:\n " + oneLineCommand, e); + } finally { + if (p != null) { + p.destroy(); + } + } + } +} diff --git a/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/SUNECReplaceFeature.java b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/SUNECReplaceFeature.java new file mode 100644 index 0000000..aa365d5 --- /dev/null +++ b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/SUNECReplaceFeature.java @@ -0,0 +1,175 @@ +package com.alibaba.confidentialcomputing.enclave; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.c.libc.LibCBase; +import com.oracle.svm.core.c.libc.TemporaryBuildDirectoryProvider; +import com.oracle.svm.core.jdk.JNIRegistrationUtil; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.ImageClassLoader; +import com.oracle.svm.hosted.NativeImageGenerator; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.hosted.Feature; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; + +import static com.alibaba.confidentialcomputing.enclave.NativeCommandUtil.GRAALVM_HOME; + +/** + * THe original {@code libsunec.a} library provided by GraalVM (which is copied from OpenJDK) has C++ operations which + * are not supported by some Enclave SDKs (e.g. OpenEnclave and Tee SDK), therefore, a substituted library that replies + * only on C symbols is required. + * <p> + * This class compiles the new C only {@code libsunec.a} and outputs it into the path specified by {@link SubstrateOptions#Path} + * options along with other SVM artifacts on demand. + */ +@AutomaticFeature +public class SUNECReplaceFeature extends JNIRegistrationUtil implements Feature { + + public static final String LIBENC_SUNEC_A = "libenc_sunec.a"; + private Path sunecTmpDir = null; + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + access.registerReachabilityHandler(this::prepareEncSunEC, + method(access, "com.alibaba.confidentialcomputing.enclave.substitutes.NativeSunECMethods", "signDigest", byte[].class, byte[].class, byte[].class, byte[].class, int.class), + method(access, "com.alibaba.confidentialcomputing.enclave.substitutes.NativeSunECMethods", "verifySignedDigest", byte[].class, byte[].class, byte[].class, byte[].class), + method(access, "com.alibaba.confidentialcomputing.enclave.substitutes.NativeSunECMethods", "isCurveSupported", byte[].class), + method(access, "com.alibaba.confidentialcomputing.enclave.substitutes.NativeSunECMethods", "generateECKeyPair", int.class, byte[].class, byte[].class), + method(access, "com.alibaba.confidentialcomputing.enclave.substitutes.NativeSunECMethods", "deriveKey", byte[].class, byte[].class, byte[].class)); + } + + @Platforms(Platform.LINUX.class) + private void prepareEncSunEC(BeforeAnalysisAccess a) { + if (Files.notExists(GRAALVM_HOME)) { + VMError.shouldNotReachHere("System environment variable GRAALVM_HOME is set to " + GRAALVM_HOME + + ", but the directory does not exist!"); + } + Path tempDirectory = ImageSingletons.lookup(TemporaryBuildDirectoryProvider.class).getTemporaryBuildDirectory(); + try { + sunecTmpDir = tempDirectory.resolve("sunec"); + if (Files.notExists(sunecTmpDir)) { + Files.createDirectory(sunecTmpDir); + } + } catch (IOException e) { + VMError.shouldNotReachHere("Can't create sunec directory in tmp directory.", e); + } + + prepareCFiles((FeatureImpl.BeforeAnalysisAccessImpl) a, sunecTmpDir); + + Path originalSunEC = GRAALVM_HOME.resolve("lib/static/linux-amd64/" + LibCBase.singleton().getName() + "/libsunec.a"); + if (Files.notExists(originalSunEC)) { + VMError.shouldNotReachHere("Can't find original libsunec.a from $GRAALVM_HOME."); + } + List<String> command = new ArrayList<>(); + // 1. Compile the C symbol only ECC_JNI.c into ENC_ECC_JNI.o + // LibCBase instance has been set in LibCFeature#afterRegistration, so it's safe to get it now. + command.add(LibCBase.singleton().getTargetCompiler()); + command.add("-fPIC"); + command.add("-I" + GRAALVM_HOME.resolve("include").toAbsolutePath().toString()); + command.add("-I" + GRAALVM_HOME.resolve("include/linux").toAbsolutePath().toString()); + command.add("-I."); + command.add("-L."); + command.add("ECC_JNI.c"); + command.add("-c"); + command.add("-o"); + command.add("ENC_ECC_JNI.o"); + NativeCommandUtil.executeNewProcess(command, sunecTmpDir); + + // 2. Extract the original libsunec.a + command.clear(); + command.add("ar"); + command.add("-x"); + command.add(originalSunEC.toAbsolutePath().toString()); + NativeCommandUtil.executeNewProcess(command, sunecTmpDir); + + // 3. Archive the ENC_ECC_JNI.o generated in step 1 and other original .o files into the new static library. + command.clear(); + // Must in the form of "/bin/bash -c", otherwise the *.o is not recognized by ProcessBuilder. + command.add("/bin/bash"); + command.add("-c"); + command.add("ar rcs " + LIBENC_SUNEC_A + " *.o"); + NativeCommandUtil.executeNewProcess(command, sunecTmpDir); + + // 4. Delete the intermediate results and only keep the static library generated by step 3. + try { + Files.walkFileTree(sunecTmpDir, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (!file.getFileName().toString().endsWith(".a")) { + Files.delete(file); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + VMError.shouldNotReachHere("Fail to delete temporary file for generating substituted libsunec.a", e); + } + } + + private static void prepareCFiles(FeatureImpl.BeforeAnalysisAccessImpl access, Path sunecTmpDir) { + ImageClassLoader imageClassLoader = access.getImageClassLoader(); + + String dir = "native/sunec/"; + List<String> cSources = new ArrayList<>(); + cSources.add("com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods.h"); + cSources.add("ecc_impl.h"); + cSources.add("ECC_JNI.c"); + cSources.add("ecl-exp.h"); + cSources.add("jlong.h"); + cSources.add("jlong_md.h"); + cSources.add("jni_util.h"); + + for (String cSource : cSources) { + File file = sunecTmpDir.resolve(cSource).toFile(); + + try (InputStream inputStream = imageClassLoader.getClassLoader().getResourceAsStream(dir + cSource); + FileOutputStream outputStream = new FileOutputStream(file)) { + if (inputStream == null) { + VMError.shouldNotReachHere("Source file " + cSource + + " doesn't exist. It is required to compile the enclave compatible libsunec.a."); + } + inputStream.transferTo(outputStream); + outputStream.flush(); + } catch (IOException e) { + VMError.shouldNotReachHere("Can't store resource file to tmp directory", e); + } + } + } + + /** + * Copy the new static library from temporary directory to the output directory. + */ + @Override + public void afterImageWrite(AfterImageWriteAccess access) { + // The sunec methods are not reachable, so the new library doesn't exist + if (sunecTmpDir == null) { + return; + } + FeatureImpl.AfterImageWriteAccessImpl a = (FeatureImpl.AfterImageWriteAccessImpl) access; + Path outputDirectory = NativeImageGenerator.generatedFiles(a.getUniverse().getBigBang().getOptions()); + + Path sunecLibrary = sunecTmpDir.resolve(LIBENC_SUNEC_A); + if (Files.exists(sunecLibrary)) { + try { + Files.copy(sunecLibrary, outputDirectory.resolve(LIBENC_SUNEC_A), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + VMError.shouldNotReachHere("Fail to copy file from temporary directory", e); + } + } + } +} diff --git a/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/NativeSunECMethods.java b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/NativeSunECMethods.java new file mode 100644 index 0000000..9b64e82 --- /dev/null +++ b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/NativeSunECMethods.java @@ -0,0 +1,21 @@ +package com.alibaba.confidentialcomputing.enclave.substitutes; + +import java.security.GeneralSecurityException; + +public class NativeSunECMethods { + public static native boolean isCurveSupported(byte[] encodedParams); + + public static native Object[] generateECKeyPair(int keySize, + byte[] encodedParams, byte[] seed) throws GeneralSecurityException; + + public static native byte[] signDigest(byte[] digest, byte[] s, + byte[] encodedParams, byte[] seed, int timing) + throws GeneralSecurityException; + + public static native boolean verifySignedDigest(byte[] signature, + byte[] digest, byte[] w, byte[] encodedParams) + throws GeneralSecurityException; + + public static native byte[] deriveKey(byte[] s, byte[] w, + byte[] encodedParams) throws GeneralSecurityException; +} diff --git a/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/SUNECSubstitutions.java b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/SUNECSubstitutions.java new file mode 100644 index 0000000..6eee323 --- /dev/null +++ b/sdk/enclave/src/main/java/com/alibaba/confidentialcomputing/enclave/substitutes/SUNECSubstitutions.java @@ -0,0 +1,53 @@ +package com.alibaba.confidentialcomputing.enclave.substitutes; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import sun.security.ec.ECDHKeyAgreement; +import sun.security.ec.ECKeyPairGenerator; + +import java.security.GeneralSecurityException; + +public class SUNECSubstitutions { + + @TargetClass(ECKeyPairGenerator.class) + public static final class Target_sun_security_ec_ECKeyPairGenerator { + @Substitute + static Object[] generateECKeyPair(int keySize, + byte[] encodedParams, byte[] seed) throws GeneralSecurityException { + return NativeSunECMethods.generateECKeyPair(keySize, encodedParams, seed); + } + + @Substitute + static boolean isCurveSupported(byte[] encodedParams) { + return NativeSunECMethods.isCurveSupported(encodedParams); + } + } + + @TargetClass(className = "sun.security.ec.ECDSASignature") + public static final class Target_sun_security_ec_ECDSASignature { + + @Substitute + static byte[] signDigest(byte[] digest, byte[] s, + byte[] encodedParams, byte[] seed, int timing) + throws GeneralSecurityException { + return NativeSunECMethods.signDigest(digest, s, encodedParams, seed, timing); + } + + @Substitute + static boolean verifySignedDigest(byte[] signature, + byte[] digest, byte[] w, byte[] encodedParams) + throws GeneralSecurityException { + return NativeSunECMethods.verifySignedDigest(signature, digest, w, encodedParams); + } + } + + @TargetClass(ECDHKeyAgreement.class) + public static final class Target_sun_security_ec_ECDHKeyAgreement { + @Substitute + static byte[] deriveKey(byte[] s, byte[] w, + byte[] encodedParams) throws GeneralSecurityException { + return NativeSunECMethods.deriveKey(s, w, encodedParams); + } + } + +} diff --git a/sdk/enclave/src/main/resources/native/sunec/ECC_JNI.c b/sdk/enclave/src/main/resources/native/sunec/ECC_JNI.c new file mode 100755 index 0000000..5b65696 --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/ECC_JNI.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include <jni.h> +#include "jni_util.h" +#include "ecc_impl.h" +#include "com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods.h" + +#define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException" +#define INVALID_ALGORITHM_PARAMETER_EXCEPTION \ + "java/security/InvalidAlgorithmParameterException" +#define INVALID_PARAMETER_EXCEPTION \ + "java/security/InvalidParameterException" +#define KEY_EXCEPTION "java/security/KeyException" + +/* + * Declare library specific JNI_Onload entry if static build + */ +JNIEXPORT jint JNICALL JNI_OnLoad_sunec(JavaVM *vm, void *reserved) { + return JNI_VERSION_1_8; +} + +/* + * Throws an arbitrary Java exception. + */ +void ThrowException_C(JNIEnv *env, const char *exceptionName) +{ + jclass exceptionClazz = (*env)->FindClass(env, exceptionName); + if (exceptionClazz != NULL) { + (*env)->ThrowNew(env, exceptionClazz, NULL); + } +} + +/* + * Deep free of the ECParams struct + */ +void FreeECParams_C(ECParams *ecparams, jboolean freeStruct) +{ + // Use B_FALSE to free the SECItem->data element, but not the SECItem itself + // Use B_TRUE to free both + + SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE); + SECITEM_FreeItem(&ecparams->curve.a, B_FALSE); + SECITEM_FreeItem(&ecparams->curve.b, B_FALSE); + SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE); + SECITEM_FreeItem(&ecparams->base, B_FALSE); + SECITEM_FreeItem(&ecparams->order, B_FALSE); + SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE); + SECITEM_FreeItem(&ecparams->curveOID, B_FALSE); + if (freeStruct) + free(ecparams); +} + +jbyteArray getEncodedBytes_C(JNIEnv *env, SECItem *hSECItem) +{ + SECItem *s = (SECItem *)hSECItem; + + jbyteArray jEncodedBytes = (*env)->NewByteArray(env, s->len); + if (jEncodedBytes == NULL) { + return NULL; + } + // Copy bytes from a native SECItem buffer to Java byte array + (*env)->SetByteArrayRegion(env, jEncodedBytes, 0, s->len, (jbyte *)s->data); + if ((*env)->ExceptionCheck(env)) { // should never happen + return NULL; + } + return jEncodedBytes; +} + +/* + * Class: sun_security_ec_ECKeyPairGenerator + * Method: isCurveSupported + * Signature: ([B)Z + */ +JNIEXPORT jboolean +JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_isCurveSupported + (JNIEnv *env, jclass clazz, jbyteArray encodedParams) +{ + SECKEYECParams params_item; + ECParams *ecparams = NULL; + jboolean result = JNI_FALSE; + + // The curve is supported if we can get parameters for it + params_item.len = (*env)->GetArrayLength(env, encodedParams); + params_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, encodedParams, 0); + if (params_item.data == NULL) { + goto cleanup; + } + + // Fill a new ECParams using the supplied OID + if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { + /* bad curve OID */ + goto cleanup; + } + + // If we make it to here, then the curve is supported + result = JNI_TRUE; + +cleanup: + { + if (params_item.data) { + (*env)->ReleaseByteArrayElements(env, encodedParams, + (jbyte *) params_item.data, JNI_ABORT); + } + if (ecparams) { + FreeECParams_C(ecparams, TRUE); + } + } + + return result; +} + +/* + * Class: sun_security_ec_ECKeyPairGenerator + * Method: generateECKeyPair + * Signature: (I[B[B)[[B + */ +JNIEXPORT jobjectArray +JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_generateECKeyPair + (JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed) +{ + ECPrivateKey *privKey = NULL; // contains both public and private values + ECParams *ecparams = NULL; + SECKEYECParams params_item; + jint jSeedLength; + jbyte* pSeedBuffer = NULL; + jobjectArray result = NULL; + jclass baCls = NULL; + jbyteArray jba; + + // Initialize the ECParams struct + params_item.len = (*env)->GetArrayLength(env, encodedParams); + params_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, encodedParams, 0); + if (params_item.data == NULL) { + goto cleanup; + } + + // Fill a new ECParams using the supplied OID + if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { + /* bad curve OID */ + ThrowException_C(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION); + goto cleanup; + } + + // Copy seed from Java to native buffer + jSeedLength = (*env)->GetArrayLength(env, seed); + pSeedBuffer = (jbyte*)malloc(jSeedLength * sizeof(jbyte)); + + (*env)->GetByteArrayRegion(env, seed, 0, jSeedLength, pSeedBuffer); + + // Generate the new keypair (using the supplied seed) + if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer, + jSeedLength, 0) != SECSuccess) { + ThrowException_C(env, KEY_EXCEPTION); + goto cleanup; + } + + jboolean isCopy; + baCls = (*env)->FindClass(env, "[B"); + if (baCls == NULL) { + goto cleanup; + } + result = (*env)->NewObjectArray(env, 2, baCls, NULL); + if (result == NULL) { + goto cleanup; + } + jba = getEncodedBytes_C(env, &(privKey->privateValue)); + if (jba == NULL) { + result = NULL; + goto cleanup; + } + (*env)->SetObjectArrayElement(env, result, 0, jba); // big integer + if ((*env)->ExceptionCheck(env)) { // should never happen + result = NULL; + goto cleanup; + } + + jba = getEncodedBytes_C(env, &(privKey->publicValue)); + if (jba == NULL) { + result = NULL; + goto cleanup; + } + (*env)->SetObjectArrayElement(env, result, 1, jba); // encoded ec point + if ((*env)->ExceptionCheck(env)) { // should never happen + result = NULL; + goto cleanup; + } + +cleanup: + { + if (params_item.data) { + (*env)->ReleaseByteArrayElements(env, encodedParams, + (jbyte *) params_item.data, JNI_ABORT); + } + if (ecparams) { + FreeECParams_C(ecparams, TRUE); + } + if (privKey) { + FreeECParams_C(&privKey->ecParams, FALSE); + SECITEM_FreeItem(&privKey->version, B_FALSE); + SECITEM_FreeItem(&privKey->privateValue, B_FALSE); + SECITEM_FreeItem(&privKey->publicValue, B_FALSE); + free(privKey); + } + + if (pSeedBuffer) { + free(pSeedBuffer); + } + } + + return result; +} + +/* + * Class: sun_security_ec_ECDSASignature + * Method: signDigest + * Signature: ([B[B[B[B)[B + */ +JNIEXPORT jbyteArray +JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_signDigest + (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing) +{ + jbyte* pDigestBuffer = NULL; + jint jDigestLength = (*env)->GetArrayLength(env, digest); + jbyteArray jSignedDigest = NULL; + + SECItem signature_item; + jbyte* pSignedDigestBuffer = NULL; + jbyteArray temp; + + jint jSeedLength = (*env)->GetArrayLength(env, seed); + jbyte* pSeedBuffer = NULL; + + // Copy digest from Java to native buffer + pDigestBuffer = (jbyte *)malloc(jDigestLength*sizeof(jbyte)); + (*env)->GetByteArrayRegion(env, digest, 0, jDigestLength, pDigestBuffer); + SECItem digest_item; + digest_item.data = (unsigned char *) pDigestBuffer; + digest_item.len = jDigestLength; + + ECPrivateKey privKey; + privKey.privateValue.data = NULL; + + // Initialize the ECParams struct + ECParams *ecparams = NULL; + SECKEYECParams params_item; + params_item.len = (*env)->GetArrayLength(env, encodedParams); + params_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, encodedParams, 0); + if (params_item.data == NULL) { + goto cleanup; + } + + // Fill a new ECParams using the supplied OID + if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { + /* bad curve OID */ + ThrowException_C(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION); + goto cleanup; + } + + // Extract private key data + privKey.ecParams = *ecparams; // struct assignment + privKey.privateValue.len = (*env)->GetArrayLength(env, privateKey); + privKey.privateValue.data = + (unsigned char *) (*env)->GetByteArrayElements(env, privateKey, 0); + if (privKey.privateValue.data == NULL) { + goto cleanup; + } + + // Prepare a buffer for the signature (twice the key length) + pSignedDigestBuffer = (jbyte *)malloc(ecparams->order.len * 2 * sizeof(jbyte)); + signature_item.data = (unsigned char *) pSignedDigestBuffer; + signature_item.len = ecparams->order.len * 2; + + // Copy seed from Java to native buffer + pSeedBuffer = (jbyte *)malloc(jSeedLength*sizeof(jbyte)); + (*env)->GetByteArrayRegion(env, seed, 0, jSeedLength, pSeedBuffer); + + // Sign the digest (using the supplied seed) + if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item, + (unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) { + ThrowException_C(env, KEY_EXCEPTION); + goto cleanup; + } + + // Create new byte array + temp = (*env)->NewByteArray(env, signature_item.len); + if (temp == NULL) { + goto cleanup; + } + + // Copy data from native buffer + (*env)->SetByteArrayRegion(env, temp, 0, signature_item.len, pSignedDigestBuffer); + jSignedDigest = temp; + +cleanup: + { + if (params_item.data) { + (*env)->ReleaseByteArrayElements(env, encodedParams, + (jbyte *) params_item.data, JNI_ABORT); + } + if (privKey.privateValue.data) { + (*env)->ReleaseByteArrayElements(env, privateKey, + (jbyte *) privKey.privateValue.data, JNI_ABORT); + } + if (pDigestBuffer) { + free(pDigestBuffer); + } + if (pSignedDigestBuffer) { + free(pSignedDigestBuffer); + } + if (pSeedBuffer) { + free(pSeedBuffer); + } + if (ecparams) { + FreeECParams_C(ecparams, TRUE); + } + } + + return jSignedDigest; +} + +/* + * Class: sun_security_ec_ECDSASignature + * Method: verifySignedDigest + * Signature: ([B[B[B[B)Z + */ +JNIEXPORT jboolean +JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_verifySignedDigest + (JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams) +{ + jboolean isValid = FALSE; + + // Copy signedDigest from Java to native buffer + jbyte* pSignedDigestBuffer = NULL; + jint jSignedDigestLength = (*env)->GetArrayLength(env, signedDigest); + pSignedDigestBuffer = (jbyte *)malloc(jSignedDigestLength*sizeof(jbyte)); + (*env)->GetByteArrayRegion(env, signedDigest, 0, jSignedDigestLength, + pSignedDigestBuffer); + SECItem signature_item; + signature_item.data = (unsigned char *) pSignedDigestBuffer; + signature_item.len = jSignedDigestLength; + + // Copy digest from Java to native buffer + jbyte* pDigestBuffer = NULL; + jint jDigestLength = (*env)->GetArrayLength(env, digest); + pDigestBuffer = (jbyte *)malloc(jDigestLength*sizeof(jbyte)); + (*env)->GetByteArrayRegion(env, digest, 0, jDigestLength, pDigestBuffer); + SECItem digest_item; + digest_item.data = (unsigned char *) pDigestBuffer; + digest_item.len = jDigestLength; + + // Extract public key data + ECPublicKey pubKey; + pubKey.publicValue.data = NULL; + ECParams *ecparams = NULL; + SECKEYECParams params_item; + + // Initialize the ECParams struct + params_item.len = (*env)->GetArrayLength(env, encodedParams); + params_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, encodedParams, 0); + if (params_item.data == NULL) { + goto cleanup; + } + + // Fill a new ECParams using the supplied OID + if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { + /* bad curve OID */ + ThrowException_C(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION); + goto cleanup; + } + pubKey.ecParams = *ecparams; // struct assignment + pubKey.publicValue.len = (*env)->GetArrayLength(env, publicKey); + pubKey.publicValue.data = + (unsigned char *) (*env)->GetByteArrayElements(env, publicKey, 0); + + if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0) + != SECSuccess) { + goto cleanup; + } + + isValid = TRUE; + +cleanup: + { + if (params_item.data) + (*env)->ReleaseByteArrayElements(env, encodedParams, + (jbyte *) params_item.data, JNI_ABORT); + + if (pubKey.publicValue.data) + (*env)->ReleaseByteArrayElements(env, publicKey, + (jbyte *) pubKey.publicValue.data, JNI_ABORT); + + if (ecparams) + FreeECParams_C(ecparams, TRUE); + + if (pSignedDigestBuffer) + free(pSignedDigestBuffer); + + if (pDigestBuffer) + free(pDigestBuffer); + } + + return isValid; +} + +/* + * Class: sun_security_ec_ECDHKeyAgreement + * Method: deriveKey + * Signature: ([B[B[B)[B + */ +JNIEXPORT jbyteArray +JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_deriveKey + (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams) +{ + jbyteArray jSecret = NULL; + ECParams *ecparams = NULL; + SECItem privateValue_item; + privateValue_item.data = NULL; + SECItem publicValue_item; + publicValue_item.data = NULL; + SECKEYECParams params_item; + params_item.data = NULL; + + // Extract private key value + privateValue_item.len = (*env)->GetArrayLength(env, privateKey); + privateValue_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, privateKey, 0); + if (privateValue_item.data == NULL) { + goto cleanup; + } + + // Extract public key value + publicValue_item.len = (*env)->GetArrayLength(env, publicKey); + publicValue_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, publicKey, 0); + if (publicValue_item.data == NULL) { + goto cleanup; + } + + // Initialize the ECParams struct + params_item.len = (*env)->GetArrayLength(env, encodedParams); + params_item.data = + (unsigned char *) (*env)->GetByteArrayElements(env, encodedParams, 0); + if (params_item.data == NULL) { + goto cleanup; + } + + // Fill a new ECParams using the supplied OID + if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { + /* bad curve OID */ + ThrowException_C(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION); + goto cleanup; + } + + // Prepare a buffer for the secret + SECItem secret_item; + secret_item.data = NULL; + secret_item.len = ecparams->order.len * 2; + + if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE, + &secret_item, 0) != SECSuccess) { + ThrowException_C(env, ILLEGAL_STATE_EXCEPTION); + goto cleanup; + } + + // Create new byte array + jSecret = (*env)->NewByteArray(env, secret_item.len); + if (jSecret == NULL) { + goto cleanup; + } + + // Copy bytes from the SECItem buffer to a Java byte array + (*env)->SetByteArrayRegion(env, jSecret, 0, secret_item.len, + (jbyte *)secret_item.data); + + // Free the SECItem data buffer + SECITEM_FreeItem(&secret_item, B_FALSE); + +cleanup: + { + if (privateValue_item.data) + (*env)->ReleaseByteArrayElements(env, privateKey, + (jbyte *) privateValue_item.data, JNI_ABORT); + + if (publicValue_item.data) + (*env)->ReleaseByteArrayElements(env, publicKey, + (jbyte *) publicValue_item.data, JNI_ABORT); + + if (params_item.data) + (*env)->ReleaseByteArrayElements(env, encodedParams, + (jbyte *) params_item.data, JNI_ABORT); + + if (ecparams) + FreeECParams_C(ecparams, TRUE); + } + + return jSecret; +} diff --git a/sdk/enclave/src/main/resources/native/sunec/com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods.h b/sdk/enclave/src/main/resources/native/sunec/com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods.h new file mode 100644 index 0000000..2586ad3 --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods.h @@ -0,0 +1,53 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods */ + +#ifndef _Included_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods +#define _Included_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods + * Method: isCurveSupported + * Signature: ([B)Z + */ +JNIEXPORT jboolean JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_isCurveSupported + (JNIEnv *, jclass, jbyteArray); + +/* + * Class: com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods + * Method: generateECKeyPair + * Signature: (I[B[B)[Ljava/lang/Object; + */ +JNIEXPORT jobjectArray JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_generateECKeyPair + (JNIEnv *, jclass, jint, jbyteArray, jbyteArray); + +/* + * Class: com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods + * Method: signDigest + * Signature: ([B[B[B[BI)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_signDigest + (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jint); + +/* + * Class: com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods + * Method: verifySignedDigest + * Signature: ([B[B[B[B)Z + */ +JNIEXPORT jboolean JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_verifySignedDigest + (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray, jbyteArray); + +/* + * Class: com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods + * Method: deriveKey + * Signature: ([B[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_alibaba_confidentialcomputing_enclave_substitutes_NativeSunECMethods_deriveKey + (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/sdk/enclave/src/main/resources/native/sunec/ecc_impl.h b/sdk/enclave/src/main/resources/native/sunec/ecc_impl.h new file mode 100755 index 0000000..48aa13a --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/ecc_impl.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* ********************************************************************* + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <[email protected]> and + * Douglas Stebila <[email protected]>, Sun Microsystems Laboratories + * + * Last Modified Date from the Original Code: May 2017 + *********************************************************************** */ + +#ifndef _ECC_IMPL_H +#define _ECC_IMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include "ecl-exp.h" + +/* + * Multi-platform definitions + */ +#ifdef __linux__ +#define B_FALSE FALSE +#define B_TRUE TRUE +typedef unsigned char uint8_t; +typedef unsigned long ulong_t; +typedef enum { B_FALSE, B_TRUE } boolean_t; +#endif /* __linux__ */ + +#ifdef _ALLBSD_SOURCE +#include <stdint.h> +#define B_FALSE FALSE +#define B_TRUE TRUE +typedef unsigned long ulong_t; +typedef enum boolean { B_FALSE, B_TRUE } boolean_t; +#endif /* _ALLBSD_SOURCE */ + +#ifdef AIX +#define B_FALSE FALSE +#define B_TRUE TRUE +typedef unsigned char uint8_t; +typedef unsigned long ulong_t; +#endif /* AIX */ + +#ifdef _WIN32 +typedef unsigned char uint8_t; +typedef unsigned long ulong_t; +typedef enum boolean { B_FALSE, B_TRUE } boolean_t; +#define strdup _strdup /* Replace POSIX name with ISO C++ name */ +#endif /* _WIN32 */ + +#ifndef _KERNEL +#include <stdlib.h> +#endif /* _KERNEL */ + +#define EC_MAX_DIGEST_LEN 1024 /* max digest that can be signed */ +#define EC_MAX_POINT_LEN 145 /* max len of DER encoded Q */ +#define EC_MAX_VALUE_LEN 72 /* max len of ANSI X9.62 private value d */ +#define EC_MAX_SIG_LEN 144 /* max signature len for supported curves */ +#define EC_MIN_KEY_LEN 112 /* min key length in bits */ +#define EC_MAX_KEY_LEN 571 /* max key length in bits */ +#define EC_MAX_OID_LEN 10 /* max length of OID buffer */ + +/* + * Various structures and definitions from NSS are here. + */ + +#ifdef _KERNEL +#define PORT_ArenaAlloc(a, n, f) kmem_alloc((n), (f)) +#define PORT_ArenaZAlloc(a, n, f) kmem_zalloc((n), (f)) +#define PORT_ArenaGrow(a, b, c, d) NULL +#define PORT_ZAlloc(n, f) kmem_zalloc((n), (f)) +#define PORT_Alloc(n, f) kmem_alloc((n), (f)) +#else +#define PORT_ArenaAlloc(a, n, f) malloc((n)) +#define PORT_ArenaZAlloc(a, n, f) calloc(1, (n)) +#define PORT_ArenaGrow(a, b, c, d) NULL +#define PORT_ZAlloc(n, f) calloc(1, (n)) +#define PORT_Alloc(n, f) malloc((n)) +#endif + +#define PORT_NewArena(b) (char *)12345 +#define PORT_ArenaMark(a) NULL +#define PORT_ArenaUnmark(a, b) +#define PORT_ArenaRelease(a, m) +#define PORT_FreeArena(a, b) +#define PORT_Strlen(s) strlen((s)) +#define PORT_SetError(e) + +#define PRBool boolean_t +#define PR_TRUE B_TRUE +#define PR_FALSE B_FALSE + +#ifdef _KERNEL +#define PORT_Assert ASSERT +#define PORT_Memcpy(t, f, l) bcopy((f), (t), (l)) +#else +#define PORT_Assert assert +#define PORT_Memcpy(t, f, l) memcpy((t), (f), (l)) +#endif + +#define CHECK_OK(func) if (func == NULL) goto cleanup +#define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup + +typedef enum { + siBuffer = 0, + siClearDataBuffer = 1, + siCipherDataBuffer = 2, + siDERCertBuffer = 3, + siEncodedCertBuffer = 4, + siDERNameBuffer = 5, + siEncodedNameBuffer = 6, + siAsciiNameString = 7, + siAsciiString = 8, + siDEROID = 9, + siUnsignedInteger = 10, + siUTCTime = 11, + siGeneralizedTime = 12 +} SECItemType; + +typedef struct SECItemStr SECItem; + +struct SECItemStr { + SECItemType type; + unsigned char *data; + unsigned int len; +}; + +typedef SECItem SECKEYECParams; + +typedef enum { ec_params_explicit, + ec_params_named +} ECParamsType; + +typedef enum { ec_field_GFp = 1, + ec_field_GF2m +} ECFieldType; + +struct ECFieldIDStr { + int size; /* field size in bits */ + ECFieldType type; + union { + SECItem prime; /* prime p for (GFp) */ + SECItem poly; /* irreducible binary polynomial for (GF2m) */ + } u; + int k1; /* first coefficient of pentanomial or + * the only coefficient of trinomial + */ + int k2; /* two remaining coefficients of pentanomial */ + int k3; +}; +typedef struct ECFieldIDStr ECFieldID; + +struct ECCurveStr { + SECItem a; /* contains octet stream encoding of + * field element (X9.62 section 4.3.3) + */ + SECItem b; + SECItem seed; +}; +typedef struct ECCurveStr ECCurve; + +typedef void PRArenaPool; + +struct ECParamsStr { + PRArenaPool * arena; + ECParamsType type; + ECFieldID fieldID; + ECCurve curve; + SECItem base; + SECItem order; + int cofactor; + SECItem DEREncoding; + ECCurveName name; + SECItem curveOID; +}; +typedef struct ECParamsStr ECParams; + +struct ECPublicKeyStr { + ECParams ecParams; + SECItem publicValue; /* elliptic curve point encoded as + * octet stream. + */ +}; +typedef struct ECPublicKeyStr ECPublicKey; + +struct ECPrivateKeyStr { + ECParams ecParams; + SECItem publicValue; /* encoded ec point */ + SECItem privateValue; /* private big integer */ + SECItem version; /* As per SEC 1, Appendix C, Section C.4 */ +}; +typedef struct ECPrivateKeyStr ECPrivateKey; + +typedef enum _SECStatus { + SECBufferTooSmall = -3, + SECWouldBlock = -2, + SECFailure = -1, + SECSuccess = 0 +} SECStatus; + +#ifdef _KERNEL +#define RNG_GenerateGlobalRandomBytes(p,l) ecc_knzero_random_generator((p), (l)) +#else +/* + This function is no longer required because the random bytes are now + supplied by the caller. Force a failure. +*/ +#define RNG_GenerateGlobalRandomBytes(p,l) SECFailure +#endif +#define CHECK_MPI_OK(func) if (MP_OKAY > (err = func)) goto cleanup +#define MP_TO_SEC_ERROR(err) + +#define SECITEM_TO_MPINT(it, mp) \ + CHECK_MPI_OK(mp_read_unsigned_octets((mp), (it).data, (it).len)) + +extern int ecc_knzero_random_generator(uint8_t *, size_t); +extern ulong_t soft_nzero_random_generator(uint8_t *, ulong_t); + +extern SECStatus EC_DecodeParams(const SECItem *, ECParams **, int); +extern SECItem * SECITEM_AllocItem(PRArenaPool *, SECItem *, unsigned int, int); +extern SECStatus SECITEM_CopyItem(PRArenaPool *, SECItem *, const SECItem *, + int); +extern void SECITEM_FreeItem(SECItem *, boolean_t); +/* This function has been modified to accept an array of random bytes */ +extern SECStatus EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey, + const unsigned char* random, int randomlen, int); +/* This function has been modified to accept an array of random bytes */ +extern SECStatus ECDSA_SignDigest(ECPrivateKey *, SECItem *, const SECItem *, + const unsigned char* random, int randomlen, int, int timing); +extern SECStatus ECDSA_VerifyDigest(ECPublicKey *, const SECItem *, + const SECItem *, int); +extern SECStatus ECDH_Derive(SECItem *, ECParams *, SECItem *, boolean_t, + SECItem *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _ECC_IMPL_H */ diff --git a/sdk/enclave/src/main/resources/native/sunec/ecl-exp.h b/sdk/enclave/src/main/resources/native/sunec/ecl-exp.h new file mode 100755 index 0000000..8b442c6 --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/ecl-exp.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* ********************************************************************* + * + * The Original Code is the elliptic curve math library. + * + * The Initial Developer of the Original Code is + * Sun Microsystems, Inc. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila <[email protected]>, Sun Microsystems Laboratories + * + *********************************************************************** */ + +#ifndef _ECL_EXP_H +#define _ECL_EXP_H + +/* Curve field type */ +typedef enum { + ECField_GFp, + ECField_GF2m +} ECField; + +/* Hexadecimal encoding of curve parameters */ +struct ECCurveParamsStr { + char *text; + ECField field; + unsigned int size; + char *irr; + char *curvea; + char *curveb; + char *genx; + char *geny; + char *order; + int cofactor; +}; +typedef struct ECCurveParamsStr ECCurveParams; + +/* Named curve parameters */ +typedef enum { + + ECCurve_noName = 0, + + /* NIST prime curves */ + ECCurve_NIST_P192, + ECCurve_NIST_P224, + ECCurve_NIST_P256, + ECCurve_NIST_P384, + ECCurve_NIST_P521, + + /* NIST binary curves */ + ECCurve_NIST_K163, + ECCurve_NIST_B163, + ECCurve_NIST_K233, + ECCurve_NIST_B233, + ECCurve_NIST_K283, + ECCurve_NIST_B283, + ECCurve_NIST_K409, + ECCurve_NIST_B409, + ECCurve_NIST_K571, + ECCurve_NIST_B571, + + /* ANSI X9.62 prime curves */ + /* ECCurve_X9_62_PRIME_192V1 == ECCurve_NIST_P192 */ + ECCurve_X9_62_PRIME_192V2, + ECCurve_X9_62_PRIME_192V3, + ECCurve_X9_62_PRIME_239V1, + ECCurve_X9_62_PRIME_239V2, + ECCurve_X9_62_PRIME_239V3, + /* ECCurve_X9_62_PRIME_256V1 == ECCurve_NIST_P256 */ + + /* ANSI X9.62 binary curves */ + ECCurve_X9_62_CHAR2_PNB163V1, + ECCurve_X9_62_CHAR2_PNB163V2, + ECCurve_X9_62_CHAR2_PNB163V3, + ECCurve_X9_62_CHAR2_PNB176V1, + ECCurve_X9_62_CHAR2_TNB191V1, + ECCurve_X9_62_CHAR2_TNB191V2, + ECCurve_X9_62_CHAR2_TNB191V3, + ECCurve_X9_62_CHAR2_PNB208W1, + ECCurve_X9_62_CHAR2_TNB239V1, + ECCurve_X9_62_CHAR2_TNB239V2, + ECCurve_X9_62_CHAR2_TNB239V3, + ECCurve_X9_62_CHAR2_PNB272W1, + ECCurve_X9_62_CHAR2_PNB304W1, + ECCurve_X9_62_CHAR2_TNB359V1, + ECCurve_X9_62_CHAR2_PNB368W1, + ECCurve_X9_62_CHAR2_TNB431R1, + + /* SEC2 prime curves */ + ECCurve_SECG_PRIME_112R1, + ECCurve_SECG_PRIME_112R2, + ECCurve_SECG_PRIME_128R1, + ECCurve_SECG_PRIME_128R2, + ECCurve_SECG_PRIME_160K1, + ECCurve_SECG_PRIME_160R1, + ECCurve_SECG_PRIME_160R2, + ECCurve_SECG_PRIME_192K1, + /* ECCurve_SECG_PRIME_192R1 == ECCurve_NIST_P192 */ + ECCurve_SECG_PRIME_224K1, + /* ECCurve_SECG_PRIME_224R1 == ECCurve_NIST_P224 */ + ECCurve_SECG_PRIME_256K1, + /* ECCurve_SECG_PRIME_256R1 == ECCurve_NIST_P256 */ + /* ECCurve_SECG_PRIME_384R1 == ECCurve_NIST_P384 */ + /* ECCurve_SECG_PRIME_521R1 == ECCurve_NIST_P521 */ + + /* SEC2 binary curves */ + ECCurve_SECG_CHAR2_113R1, + ECCurve_SECG_CHAR2_113R2, + ECCurve_SECG_CHAR2_131R1, + ECCurve_SECG_CHAR2_131R2, + /* ECCurve_SECG_CHAR2_163K1 == ECCurve_NIST_K163 */ + ECCurve_SECG_CHAR2_163R1, + /* ECCurve_SECG_CHAR2_163R2 == ECCurve_NIST_B163 */ + ECCurve_SECG_CHAR2_193R1, + ECCurve_SECG_CHAR2_193R2, + /* ECCurve_SECG_CHAR2_233K1 == ECCurve_NIST_K233 */ + /* ECCurve_SECG_CHAR2_233R1 == ECCurve_NIST_B233 */ + ECCurve_SECG_CHAR2_239K1, + /* ECCurve_SECG_CHAR2_283K1 == ECCurve_NIST_K283 */ + /* ECCurve_SECG_CHAR2_283R1 == ECCurve_NIST_B283 */ + /* ECCurve_SECG_CHAR2_409K1 == ECCurve_NIST_K409 */ + /* ECCurve_SECG_CHAR2_409R1 == ECCurve_NIST_B409 */ + /* ECCurve_SECG_CHAR2_571K1 == ECCurve_NIST_K571 */ + /* ECCurve_SECG_CHAR2_571R1 == ECCurve_NIST_B571 */ + + /* WTLS curves */ + ECCurve_WTLS_1, + /* there is no WTLS 2 curve */ + /* ECCurve_WTLS_3 == ECCurve_NIST_K163 */ + /* ECCurve_WTLS_4 == ECCurve_SECG_CHAR2_113R1 */ + /* ECCurve_WTLS_5 == ECCurve_X9_62_CHAR2_PNB163V1 */ + /* ECCurve_WTLS_6 == ECCurve_SECG_PRIME_112R1 */ + /* ECCurve_WTLS_7 == ECCurve_SECG_PRIME_160R1 */ + ECCurve_WTLS_8, + ECCurve_WTLS_9, + /* ECCurve_WTLS_10 == ECCurve_NIST_K233 */ + /* ECCurve_WTLS_11 == ECCurve_NIST_B233 */ + /* ECCurve_WTLS_12 == ECCurve_NIST_P224 */ + + /* ECC Brainpool prime curves in RFC 5639*/ + ECCurve_BrainpoolP256r1, + ECCurve_BrainpoolP320r1, + ECCurve_BrainpoolP384r1, + ECCurve_BrainpoolP512r1, + + ECCurve_pastLastCurve +} ECCurveName; + +/* Aliased named curves */ + +#define ECCurve_X9_62_PRIME_192V1 ECCurve_NIST_P192 +#define ECCurve_X9_62_PRIME_256V1 ECCurve_NIST_P256 +#define ECCurve_SECG_PRIME_192R1 ECCurve_NIST_P192 +#define ECCurve_SECG_PRIME_224R1 ECCurve_NIST_P224 +#define ECCurve_SECG_PRIME_256R1 ECCurve_NIST_P256 +#define ECCurve_SECG_PRIME_384R1 ECCurve_NIST_P384 +#define ECCurve_SECG_PRIME_521R1 ECCurve_NIST_P521 +#define ECCurve_SECG_CHAR2_163K1 ECCurve_NIST_K163 +#define ECCurve_SECG_CHAR2_163R2 ECCurve_NIST_B163 +#define ECCurve_SECG_CHAR2_233K1 ECCurve_NIST_K233 +#define ECCurve_SECG_CHAR2_233R1 ECCurve_NIST_B233 +#define ECCurve_SECG_CHAR2_283K1 ECCurve_NIST_K283 +#define ECCurve_SECG_CHAR2_283R1 ECCurve_NIST_B283 +#define ECCurve_SECG_CHAR2_409K1 ECCurve_NIST_K409 +#define ECCurve_SECG_CHAR2_409R1 ECCurve_NIST_B409 +#define ECCurve_SECG_CHAR2_571K1 ECCurve_NIST_K571 +#define ECCurve_SECG_CHAR2_571R1 ECCurve_NIST_B571 +#define ECCurve_WTLS_3 ECCurve_NIST_K163 +#define ECCurve_WTLS_4 ECCurve_SECG_CHAR2_113R1 +#define ECCurve_WTLS_5 ECCurve_X9_62_CHAR2_PNB163V1 +#define ECCurve_WTLS_6 ECCurve_SECG_PRIME_112R1 +#define ECCurve_WTLS_7 ECCurve_SECG_PRIME_160R1 +#define ECCurve_WTLS_10 ECCurve_NIST_K233 +#define ECCurve_WTLS_11 ECCurve_NIST_B233 +#define ECCurve_WTLS_12 ECCurve_NIST_P224 + +#endif /* _ECL_EXP_H */ diff --git a/sdk/enclave/src/main/resources/native/sunec/jlong.h b/sdk/enclave/src/main/resources/native/sunec/jlong.h new file mode 100755 index 0000000..40fd9f1 --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/jlong.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _JLONG_H_ +#define _JLONG_H_ + +#include "jlong_md.h" + +#endif diff --git a/sdk/enclave/src/main/resources/native/sunec/jlong_md.h b/sdk/enclave/src/main/resources/native/sunec/jlong_md.h new file mode 100755 index 0000000..40fb0af --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/jlong_md.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef _SOLARIS_JLONG_MD_H_ +#define _SOLARIS_JLONG_MD_H_ + +/* Make sure ptrdiff_t is defined */ +#include <stddef.h> +#include <stdint.h> /* For uintptr_t */ + +#define jlong_high(a) ((jint)((a)>>32)) +#define jlong_low(a) ((jint)(a)) +#define jlong_add(a, b) ((a) + (b)) +#define jlong_and(a, b) ((a) & (b)) +#define jlong_div(a, b) ((a) / (b)) +#define jlong_mul(a, b) ((a) * (b)) +#define jlong_neg(a) (-(a)) +#define jlong_not(a) (~(a)) +#define jlong_or(a, b) ((a) | (b)) +#define jlong_shl(a, n) ((a) << (n)) +#define jlong_shr(a, n) ((a) >> (n)) +#define jlong_sub(a, b) ((a) - (b)) +#define jlong_xor(a, b) ((a) ^ (b)) +#define jlong_rem(a,b) ((a) % (b)) + +/* comparison operators */ +#define jlong_ltz(ll) ((ll)<0) +#define jlong_gez(ll) ((ll)>=0) +#define jlong_gtz(ll) ((ll)>0) +#define jlong_eqz(a) ((a) == 0) +#define jlong_eq(a, b) ((a) == (b)) +#define jlong_ne(a,b) ((a) != (b)) +#define jlong_ge(a,b) ((a) >= (b)) +#define jlong_le(a,b) ((a) <= (b)) +#define jlong_lt(a,b) ((a) < (b)) +#define jlong_gt(a,b) ((a) > (b)) + +#define jlong_zero ((jlong) 0) +#define jlong_one ((jlong) 1) +#define jlong_minus_one ((jlong) -1) + +/* For static variables initialized to zero */ +#define jlong_zero_init ((jlong) 0L) + +#ifdef _LP64 + #ifndef jlong_to_ptr + #define jlong_to_ptr(a) ((void*)(a)) + #endif + #ifndef ptr_to_jlong + #define ptr_to_jlong(a) ((jlong)(a)) + #endif +#else + #ifndef jlong_to_ptr + #define jlong_to_ptr(a) ((void*)(int)(a)) + #endif + #ifndef ptr_to_jlong + #define ptr_to_jlong(a) ((jlong)(int)(a)) + #endif +#endif + +#define jint_to_jlong(a) ((jlong)(a)) +#define jlong_to_jint(a) ((jint)(a)) + +/* Useful on machines where jlong and jdouble have different endianness. */ +#define jlong_to_jdouble_bits(a) +#define jdouble_to_jlong_bits(a) + +#define jlong_to_int(a) ((int)(a)) +#define int_to_jlong(a) ((jlong)(a)) +#define jlong_to_uint(a) ((unsigned int)(a)) +#define uint_to_jlong(a) ((jlong)(a)) +#define jlong_to_ptrdiff(a) ((ptrdiff_t)(a)) +#define ptrdiff_to_jlong(a) ((jlong)(a)) +#define jlong_to_size(a) ((size_t)(a)) +#define size_to_jlong(a) ((jlong)(a)) +#define long_to_jlong(a) ((jlong)(a)) + +#endif /* !_SOLARIS_JLONG_MD_H_ */ diff --git a/sdk/enclave/src/main/resources/native/sunec/jni_util.h b/sdk/enclave/src/main/resources/native/sunec/jni_util.h new file mode 100755 index 0000000..baeb10d --- /dev/null +++ b/sdk/enclave/src/main/resources/native/sunec/jni_util.h @@ -0,0 +1,534 @@ +/* + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef JNI_UTIL_H +#define JNI_UTIL_H + +#include "jni.h" +#include "jlong.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains utility functions that can be implemented in pure JNI. + * + * Caution: Callers of functions declared in this file should be + * particularly aware of the fact that these functions are convenience + * functions, and as such are often compound operations, each one of + * which may throw an exception. Therefore, the functions this file + * will often return silently if an exception has occurred, and callers + * must check for exception themselves. + */ + +/* Throw a Java exception by name. Similar to SignalError. */ +JNIEXPORT void JNICALL +JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg); + +/* Throw common exceptions */ +JNIEXPORT void JNICALL +JNU_ThrowNullPointerException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowArrayIndexOutOfBoundsException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowOutOfMemoryError(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowIllegalArgumentException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowIllegalAccessError(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowIllegalAccessException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowInternalError(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowIOException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowNoSuchFieldException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowNoSuchMethodException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowClassNotFoundException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowNumberFormatException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowNoSuchFieldError(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowNoSuchMethodError(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowStringIndexOutOfBoundsException(JNIEnv *env, const char *msg); + +JNIEXPORT void JNICALL +JNU_ThrowInstantiationException(JNIEnv *env, const char *msg); + +/* Throw an exception by name, using the string returned by + * getLastErrorString for the detail string. If the last-error + * string is NULL, use the given default detail string. + */ +JNIEXPORT void JNICALL +JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name, + const char *defaultDetail); + +/* Throw an exception by name, using a given message and the string + * returned by getLastErrorString to construct the detail string. + */ +JNIEXPORT void JNICALL +JNU_ThrowByNameWithMessageAndLastError + (JNIEnv *env, const char *name, const char *message); + +/* Throw an IOException, using the last-error string for the detail + * string. If the last-error string is NULL, use the given default + * detail string. + */ +JNIEXPORT void JNICALL +JNU_ThrowIOExceptionWithLastError(JNIEnv *env, const char *defaultDetail); + +/* Convert between Java strings and i18n C strings */ +JNIEXPORT jstring +NewStringPlatform(JNIEnv *env, const char *str); + +JNIEXPORT const char * +GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy); + +JNIEXPORT jstring JNICALL +JNU_NewStringPlatform(JNIEnv *env, const char *str); + +JNIEXPORT const char * JNICALL +JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy); + +JNIEXPORT void JNICALL +JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str); + +/* Class constants */ +JNIEXPORT jclass JNICALL +JNU_ClassString(JNIEnv *env); + +JNIEXPORT jclass JNICALL +JNU_ClassClass(JNIEnv *env); + +JNIEXPORT jclass JNICALL +JNU_ClassObject(JNIEnv *env); + +JNIEXPORT jclass JNICALL +JNU_ClassThrowable(JNIEnv *env); + +/* Copy count number of arguments from src to dst. Array bounds + * and ArrayStoreException are checked. + */ +JNIEXPORT jint JNICALL +JNU_CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src, + jint count); + +/* Invoke a object-returning static method, based on class name, + * method name, and signature string. + * + * The caller should check for exceptions by setting hasException + * argument. If the caller is not interested in whether an exception + * has occurred, pass in NULL. + */ +JNIEXPORT jvalue JNICALL +JNU_CallStaticMethodByName(JNIEnv *env, + jboolean *hasException, + const char *class_name, + const char *name, + const char *signature, + ...); + +/* Invoke an instance method by name. + */ +JNIEXPORT jvalue JNICALL +JNU_CallMethodByName(JNIEnv *env, + jboolean *hasException, + jobject obj, + const char *name, + const char *signature, + ...); + +JNIEXPORT jvalue JNICALL +JNU_CallMethodByNameV(JNIEnv *env, + jboolean *hasException, + jobject obj, + const char *name, + const char *signature, + va_list args); + +/* Construct a new object of class, specifying the class by name, + * and specififying which constructor to run and what arguments to + * pass to it. + * + * The method will return an initialized instance if successful. + * It will return NULL if an error has occurred (for example if + * it ran out of memory) and the appropriate Java exception will + * have been thrown. + */ +JNIEXPORT jobject JNICALL +JNU_NewObjectByName(JNIEnv *env, const char *class_name, + const char *constructor_sig, ...); + +/* returns: + * 0: object is not an instance of the class named by classname. + * 1: object is an instance of the class named by classname. + * -1: the class named by classname cannot be found. An exception + * has been thrown. + */ +JNIEXPORT jint JNICALL +JNU_IsInstanceOfByName(JNIEnv *env, jobject object, char *classname); + + +/* Get or set class and instance fields. + * Note that set functions take a variable number of arguments, + * but only one argument of the appropriate type can be passed. + * For example, to set an integer field i to 100: + * + * JNU_SetFieldByName(env, &exc, obj, "i", "I", 100); + * + * To set a float field f to 12.3: + * + * JNU_SetFieldByName(env, &exc, obj, "f", "F", 12.3); + * + * The caller should check for exceptions by setting hasException + * argument. If the caller is not interested in whether an exception + * has occurred, pass in NULL. + */ +JNIEXPORT jvalue JNICALL +JNU_GetFieldByName(JNIEnv *env, + jboolean *hasException, + jobject obj, + const char *name, + const char *sig); +JNIEXPORT void JNICALL +JNU_SetFieldByName(JNIEnv *env, + jboolean *hasException, + jobject obj, + const char *name, + const char *sig, + ...); + +JNIEXPORT jvalue JNICALL +JNU_GetStaticFieldByName(JNIEnv *env, + jboolean *hasException, + const char *classname, + const char *name, + const char *sig); +JNIEXPORT void JNICALL +JNU_SetStaticFieldByName(JNIEnv *env, + jboolean *hasException, + const char *classname, + const char *name, + const char *sig, + ...); + + +/* + * Calls the .equals method. + */ +JNIEXPORT jboolean JNICALL +JNU_Equals(JNIEnv *env, jobject object1, jobject object2); + + +/************************************************************************ + * Thread calls + * + * Convenience thread-related calls on the java.lang.Object class. + */ + +JNIEXPORT void JNICALL +JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout); + +JNIEXPORT void JNICALL +JNU_Notify(JNIEnv *env, jobject object); + +JNIEXPORT void JNICALL +JNU_NotifyAll(JNIEnv *env, jobject object); + + +/************************************************************************ + * Miscellaneous utilities used by the class libraries + */ + +#define IS_NULL(obj) ((obj) == NULL) +#define JNU_IsNull(env,obj) ((obj) == NULL) + +/************************************************************************ + * Miscellaneous utilities used by the class libraries to return from + * a function if a value is NULL or an exception is pending. + */ + +#define CHECK_NULL(x) \ + do { \ + if ((x) == NULL) { \ + return; \ + } \ + } while (0) \ + +#define CHECK_NULL_THROW_NPE(env, x, msg) \ + do { \ + if ((x) == NULL) { \ + JNU_ThrowNullPointerException((env), (msg));\ + return; \ + } \ + } while(0) \ + +#define CHECK_NULL_THROW_NPE_RETURN(env, x, msg, z)\ + do { \ + if ((x) == NULL) { \ + JNU_ThrowNullPointerException((env), (msg));\ + return (z); \ + } \ + } while(0) \ + +#define CHECK_NULL_RETURN(x, y) \ + do { \ + if ((x) == NULL) { \ + return (y); \ + } \ + } while (0) \ + +#ifdef __cplusplus +#define JNU_CHECK_EXCEPTION(env) \ + do { \ + if ((env)->ExceptionCheck()) { \ + return; \ + } \ + } while (0) \ + +#define JNU_CHECK_EXCEPTION_RETURN(env, y) \ + do { \ + if ((env)->ExceptionCheck()) { \ + return (y); \ + } \ + } while (0) +#else +#define JNU_CHECK_EXCEPTION(env) \ + do { \ + if ((*env)->ExceptionCheck(env)) { \ + return; \ + } \ + } while (0) \ + +#define JNU_CHECK_EXCEPTION_RETURN(env, y) \ + do { \ + if ((*env)->ExceptionCheck(env)) { \ + return (y); \ + } \ + } while (0) +#endif /* __cplusplus */ +/************************************************************************ + * Debugging utilities + */ + +JNIEXPORT void JNICALL +JNU_PrintString(JNIEnv *env, char *hdr, jstring string); + +JNIEXPORT void JNICALL +JNU_PrintClass(JNIEnv *env, char *hdr, jobject object); + +JNIEXPORT jstring JNICALL +JNU_ToString(JNIEnv *env, jobject object); + +/* + * Package shorthand for use by native libraries + */ +#define JNU_JAVAPKG "java/lang/" +#define JNU_JAVAIOPKG "java/io/" +#define JNU_JAVANETPKG "java/net/" + +/* + * Check if the current thread is attached to the VM, and returns + * the JNIEnv of the specified version if the thread is attached. + * + * If the current thread is not attached, this function returns 0. + * + * If the current thread is attached, this function returns the + * JNI environment, or returns (void *)JNI_ERR if the specified + * version is not supported. + */ +JNIEXPORT void * JNICALL +JNU_GetEnv(JavaVM *vm, jint version); + +/* + * Warning free access to pointers stored in Java long fields. + */ +#define JNU_GetLongFieldAsPtr(env,obj,id) \ + (jlong_to_ptr((*(env))->GetLongField((env),(obj),(id)))) +#define JNU_SetLongFieldFromPtr(env,obj,id,val) \ + (*(env))->SetLongField((env),(obj),(id),ptr_to_jlong(val)) + +/* + * Internal use only. + */ +enum { + NO_ENCODING_YET = 0, /* "sun.jnu.encoding" not yet set */ + NO_FAST_ENCODING, /* Platform encoding is not fast */ + FAST_8859_1, /* ISO-8859-1 */ + FAST_CP1252, /* MS-DOS Cp1252 */ + FAST_646_US, /* US-ASCII : ISO646-US */ + FAST_UTF_8 +}; + +int getFastEncoding(); + +JNIEXPORT void InitializeEncoding(JNIEnv *env, const char *name); + +void* getProcessHandle(); + +void buildJniFunctionName(const char *sym, const char *cname, + char *jniEntryName); + +JNIEXPORT size_t JNICALL +getLastErrorString(char *buf, size_t len); + +JNIEXPORT int JNICALL +getErrorString(int err, char *buf, size_t len); + +#ifdef STATIC_BUILD +/* Macros for handling declaration of static/dynamic + * JNI library Load/Unload functions + * + * Use DEF_JNI_On{Un}Load when you want a static and non-static entry points. + * Use DEF_STATIC_JNI_On{Un}Load when you only want a static one. + * + * LIBRARY_NAME must be set to the name of the library + */ + +/* These three macros are needed to get proper concatenation of + * the LIBRARY_NAME + * + * NOTE: LIBRARY_NAME must be set for static builds. + */ +#define ADD_LIB_NAME3(name, lib) name ## lib +#define ADD_LIB_NAME2(name, lib) ADD_LIB_NAME3(name, lib) +#define ADD_LIB_NAME(entry) ADD_LIB_NAME2(entry, LIBRARY_NAME) + +#define DEF_JNI_OnLoad \ +ADD_LIB_NAME(JNI_OnLoad_)(JavaVM *vm, void *reserved) \ +{ \ + jint JNICALL ADD_LIB_NAME(JNI_OnLoad_dynamic_)(JavaVM *vm, void *reserved); \ + ADD_LIB_NAME(JNI_OnLoad_dynamic_)(vm, reserved); \ + return JNI_VERSION_1_8; \ +} \ +jint JNICALL ADD_LIB_NAME(JNI_OnLoad_dynamic_) + +#define DEF_STATIC_JNI_OnLoad \ +JNIEXPORT jint JNICALL ADD_LIB_NAME(JNI_OnLoad_)(JavaVM *vm, void *reserved) { \ + return JNI_VERSION_1_8; \ +} + +#define DEF_JNI_OnUnload \ +ADD_LIB_NAME(JNI_OnUnload_)(JavaVM *vm, void *reserved) \ +{ \ + void JNICALL ADD_LIB_NAME(JNI_OnUnload_dynamic_)(JavaVM *vm, void *reserved); \ + ADD_LIB_NAME(JNI_OnUnload_dynamic_)(vm, reserved); \ +} \ +void JNICALL ADD_LIB_NAME(JNI_OnUnload_dynamic_) + +#define DEF_STATIC_JNI_OnUnload \ +ADD_LIB_NAME(JNI_OnUnload_) + +#else + +#define DEF_JNI_OnLoad JNI_OnLoad +#define DEF_STATIC_JNI_OnLoad +#define DEF_JNI_OnUnload JNI_OnUnload +#define DEF_STATIC_JNI_OnUnload +#endif + +#ifdef STATIC_BUILD +/* Macros for handling declaration of static/dynamic + * Agent library Load/Attach/Unload functions + * + * Use DEF_Agent_OnLoad, DEF_Agent_OnAttach or DEF_Agent_OnUnload + * when you want both static and non-static entry points. + * Use DEF_STATIC_Agent_OnLoad, DEF_STATIC_Agent_OnAttach or + * DEF_STATIC_Agent_OnUnload when you only want a static one. + * + * LIBRARY_NAME must be set to the name of the library for static builds. + */ + +#define DEF_Agent_OnLoad \ +ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) \ +{ \ + jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)(JavaVM *vm, char *options, void *reserved); \ + return ADD_LIB_NAME(Agent_OnLoad_dynamic_)(vm, options, reserved); \ +} \ +jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_) + +#define DEF_STATIC_Agent_OnLoad \ +JNIEXPORT jint JNICALL ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) { \ + return JNI_FALSE; \ +} + +#define DEF_Agent_OnAttach \ +ADD_LIB_NAME(Agent_OnAttach_)(JavaVM *vm, char *options, void *reserved) \ +{ \ + jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)(JavaVM *vm, char *options, void *reserved); \ + return ADD_LIB_NAME(Agent_OnAttach_dynamic_)(vm, options, reserved); \ +} \ +jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_) + +#define DEF_STATIC_Agent_OnAttach \ +JNIEXPORT jint JNICALL ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) { \ + return JNI_FALSE; \ +} + +#define DEF_Agent_OnUnload \ +ADD_LIB_NAME(Agent_OnUnload_)(JavaVM *vm) \ +{ \ + void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)(JavaVM *vm); \ + ADD_LIB_NAME(Agent_OnUnload_dynamic_)(vm); \ +} \ +void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_) + +#define DEF_STATIC_Agent_OnUnload \ +ADD_LIB_NAME(Agent_OnUnload_) + +#else +#define DEF_Agent_OnLoad Agent_OnLoad +#define DEF_Agent_OnAttach Agent_OnAttach +#define DEF_Agent_OnUnload Agent_OnUnload +#define DEF_STATIC_Agent_OnLoad +#define DEF_STATIC_Agent_OnAttach +#define DEF_STATIC_Agent_OnUnload +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* JNI_UTIL_H */ diff --git a/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/NativeImageTest.java b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/NativeImageTest.java index 43e5e37..99296d9 100644 --- a/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/NativeImageTest.java +++ b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/NativeImageTest.java @@ -1,11 +1,7 @@ package com.alibaba.confidentialcomputing.enclave; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.SequenceInputStream; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -16,9 +12,11 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static com.alibaba.confidentialcomputing.enclave.NativeCommandUtil.GRAALVM_HOME; +import static com.alibaba.confidentialcomputing.enclave.SUNECReplaceFeature.LIBENC_SUNEC_A; + public abstract class NativeImageTest implements NativeImageTestable { private static final String JNI_LIB_NAME = "encinvokeentrytest"; - public static final Path GRAALVM_HOME = Paths.get(System.getenv("GRAALVM_HOME")); public static final Path MVN_BUILD_DIR = Paths.get("target"); private static final String SVM_OUT = "svm-out"; private static final String SVM_ENCLAVE_LIB = "svm_enclave_sdk"; @@ -179,7 +177,7 @@ public abstract class NativeImageTest implements NativeImageTestable { if (extraOptions != null && !extraOptions.isEmpty()) { command.addAll(extraOptions); } - NativeImageTest.executeNewProcess(command, workingDir); + NativeCommandUtil.executeNewProcess(command, workingDir); } private void compileJNILibrary() { @@ -204,7 +202,7 @@ public abstract class NativeImageTest implements NativeImageTestable { prepareDynamicLinkingCommand(command); } command.addAll(addMacros()); - executeNewProcess(command, workingDir); + NativeCommandUtil.executeNewProcess(command, workingDir); } protected Collection<String> addMacros(){ @@ -229,7 +227,9 @@ public abstract class NativeImageTest implements NativeImageTestable { command.add(graalvmHome.resolve("lib/static/linux-amd64/musl/libzip.a").toString()); command.add(graalvmHome.resolve("lib/static/linux-amd64/musl/libnet.a").toString()); command.add(graalvmHome.resolve("lib/static/linux-amd64/musl/libjava.a").toString()); - command.add(graalvmHome.resolve("lib/static/linux-amd64/musl/libsunec.a").toString()); + if (Files.exists(svmOutputDir.toAbsolutePath().resolve(LIBENC_SUNEC_A))) { + command.add(svmOutputDir.toAbsolutePath().resolve(LIBENC_SUNEC_A).toString()); + } command.add(graalvmHome.resolve("lib/static/linux-amd64/musl/libfdlibm.a").toString()); command.add("-std=c99"); command.add("-lc"); @@ -254,40 +254,6 @@ public abstract class NativeImageTest implements NativeImageTestable { command.add("lib" + JNI_LIB_NAME + ".so"); } - public static int executeNewProcess(List<String> command, Path workDir) { - if (command == null || command.isEmpty()) { - throw new RuntimeException("Didn't provide any execution command."); - } - ProcessBuilder pb = new ProcessBuilder(command).directory(workDir.toFile()); - String oneLineCommand = command.stream().reduce((e1, e2) -> e1 + " " + e2).orElse(""); - System.out.println(oneLineCommand); - Process p = null; - try { - p = pb.start(); - SequenceInputStream sis = new SequenceInputStream(p.getInputStream(), p.getErrorStream()); - InputStreamReader inst = new InputStreamReader(sis, StandardCharsets.UTF_8); - StringBuilder sb = new StringBuilder(); - try (BufferedReader br = new BufferedReader(inst)) { - String res; - while ((res = br.readLine()) != null) { - sb.append(res).append("\n"); - } - } - System.out.println(sb); - int exitCode = p.waitFor(); - if (exitCode != 0) { - throw new RuntimeException("Failed to execute command:\n " + oneLineCommand + - "\n Working directory is :" + workDir.toString() + "\n The exit code is " + exitCode); - } - return 0; - } catch (IOException | InterruptedException e) { - throw new RuntimeException("Failed to execute command:\n " + oneLineCommand, e); - } finally { - if (p != null) { - p.destroy(); - } - } - } public static void copyFile(Path source, Path dest, String errMSg) { try { diff --git a/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/ReplaceSunECTest.java b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/ReplaceSunECTest.java new file mode 100644 index 0000000..8034352 --- /dev/null +++ b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/ReplaceSunECTest.java @@ -0,0 +1,78 @@ +package com.alibaba.confidentialcomputing.enclave; + +import com.alibaba.confidentialcomputing.enclave.testservice.EncryptionService; +import com.alibaba.confidentialcomputing.enclave.testservice.SunECOperations; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.hosted.FeatureImpl; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeSerialization; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import sun.security.ec.ECKeyPairGenerator; + +import java.security.KeyPair; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ReplaceSunECTest { + + private static final String ENCRYPT_SERVICE = "com.alibaba.confidentialcomputing.enclave.testservice.EncryptionService"; + private static final String SUNEC_OP = "com.alibaba.confidentialcomputing.enclave.testservice.SunECOperations"; + @TestTarget(ReplaceSunECTest.class) + static class ReplaceSunECPreparation extends NativeImageTest{ + + @Override + SVMCompileElements specifyTestClasses() { + SVMCompileElements ret = new SVMCompileElements(); + // Specify the service file + ret.addServices("META-INF/services/"+ENCRYPT_SERVICE); + ret.addClasses(EncryptionService.class, SunECOperations.class, UTFeature.class); + return ret; + } + +/* @Override + public List<String> extraSVMOptions() { + return List.of("--debug-attach:5005"); + }*/ + } + + @BeforeAll + public static void prepareLibraries(){ + new ReplaceSunECPreparation().prepareNativeLibraries(); + } + + @BeforeEach + public void setup() { + EnclaveTestHelper.createIsolate(); + } + + @AfterEach + public void teardown() { + EnclaveTestHelper.destroyIsolate(); + } + + @Test + public void test(){ + String id = EnclaveTestHelper.loadAndGetService(ENCRYPT_SERVICE, SUNEC_OP, 1); + KeyPair remoteRet = (KeyPair)EnclaveTestHelper.call(id, ENCRYPT_SERVICE, SUNEC_OP, "generateKeyPair", EnclaveTestHelper.EMPTY_STRING_ARRAY, EnclaveTestHelper.EMPTY_OBJECT_ARRAY); + assertNotNull(remoteRet); + } + + @AutomaticFeature + static class UTFeature implements Feature { + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + FeatureImpl.BeforeAnalysisAccessImpl a = (FeatureImpl.BeforeAnalysisAccessImpl)access; + Class<?> PKCS8KeyClass = a.getImageClassLoader().findClass("sun.security.pkcs.PKCS8Key").get(); + Class<?> X509KeyClass = a.getImageClassLoader().findClass("sun.security.x509.X509Key").get(); + RuntimeSerialization.register(PKCS8KeyClass, X509KeyClass); + RuntimeSerialization.registerAllAssociatedClasses(java.security.KeyRep.class); + RuntimeSerialization.registerAllAssociatedClasses(sun.security.ec.ECPrivateKeyImpl.class); + RuntimeSerialization.registerAllAssociatedClasses(sun.security.ec.ECPublicKeyImpl.class); + } + } +} diff --git a/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/EncryptionService.java b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/EncryptionService.java new file mode 100644 index 0000000..9c5b770 --- /dev/null +++ b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/EncryptionService.java @@ -0,0 +1,10 @@ +package com.alibaba.confidentialcomputing.enclave.testservice; + +import com.alibaba.confidentialcomputing.common.annotations.EnclaveService; + +import java.security.KeyPair; + +@EnclaveService +public interface EncryptionService { + KeyPair generateKeyPair(); +} diff --git a/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/SunECOperations.java b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/SunECOperations.java new file mode 100644 index 0000000..dfbdab9 --- /dev/null +++ b/sdk/enclave/src/test/java/com/alibaba/confidentialcomputing/enclave/testservice/SunECOperations.java @@ -0,0 +1,12 @@ +package com.alibaba.confidentialcomputing.enclave.testservice; + +import java.security.KeyPair; +import sun.security.ec.ECKeyPairGenerator; + +public class SunECOperations implements EncryptionService{ + @Override + public KeyPair generateKeyPair() { + ECKeyPairGenerator pairGenerator = new ECKeyPairGenerator(); + return pairGenerator.generateKeyPair(); + } +} diff --git a/sdk/enclave/src/test/resources/META-INF/services/com.alibaba.confidentialcomputing.enclave.testservice.EncryptionService b/sdk/enclave/src/test/resources/META-INF/services/com.alibaba.confidentialcomputing.enclave.testservice.EncryptionService new file mode 100644 index 0000000..86f677c --- /dev/null +++ b/sdk/enclave/src/test/resources/META-INF/services/com.alibaba.confidentialcomputing.enclave.testservice.EncryptionService @@ -0,0 +1 @@ +com.alibaba.confidentialcomputing.enclave.testservice.SunECOperations \ No newline at end of file diff --git a/tools/cicd/make.sh b/tools/cicd/make.sh index fd768b7..6da95c9 100755 --- a/tools/cicd/make.sh +++ b/tools/cicd/make.sh @@ -1,7 +1,7 @@ #!/bin/bash BUILD_IMAGE=javaenclave_build -BUILD_TAG=v0.1.3 +BUILD_TAG=v0.1.6 SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
