From dd15ed6c6a8d15c2059409d699d98719f70debca Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 14:44:09 +0530 Subject: [PATCH 1/6] Add new APIs to read EC public and private keys from files --- ballerina/private_public_key.bal | 26 +++++++++ ballerina/tests/private_public_key_test.bal | 22 ++++++++ ballerina/tests/resources/ec-cert.crt | 18 ++++++ ballerina/tests/test_utils.bal | 2 + changelog.md | 5 ++ docs/spec/spec.md | 56 +++++++++++++++++-- .../stdlib/crypto/nativeimpl/Decode.java | 33 ++++++++++- 7 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 ballerina/tests/resources/ec-cert.crt diff --git a/ballerina/private_public_key.bal b/ballerina/private_public_key.bal index a667388f..d37ffe59 100644 --- a/ballerina/private_public_key.bal +++ b/ballerina/private_public_key.bal @@ -128,6 +128,20 @@ public isolated function decodeRsaPrivateKeyFromKeyFile(string keyFile, string? 'class: "io.ballerina.stdlib.crypto.nativeimpl.Decode" } external; +# Decodes the EC private key from the given private key and private key password. +# ```ballerina +# string keyFile = "/path/to/private.key"; +# crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyFile(keyFile, "keyPassword"); +# ``` +# +# + keyFile - Path to the key file +# + keyPassword - Password of the key file if it is encrypted +# + return - Reference to the private key or else a `crypto:Error` if the private key was unreadable +public isolated function decodeEcPrivateKeyFromKeyFile(string keyFile, string? keyPassword = ()) + returns PrivateKey|Error = @java:Method { + 'class: "io.ballerina.stdlib.crypto.nativeimpl.Decode" +} external; + # Decodes the RSA public key from the given PKCS#12 archive file. # ```ballerina # crypto:TrustStore trustStore = { @@ -174,6 +188,18 @@ public isolated function decodeRsaPublicKeyFromCertFile(string certFile) returns 'class: "io.ballerina.stdlib.crypto.nativeimpl.Decode" } external; +# Decodes the EC public key from the given public certificate file. +# ```ballerina +# string certFile = "/path/to/public.cert"; +# crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromCertFile(certFile); +# ``` +# +# + certFile - Path to the certificate file +# + return - Reference to the public key or else a `crypto:Error` if the public key was unreadable +public isolated function decodeEcPublicKeyFromCertFile(string certFile) returns PublicKey|Error = @java:Method { + 'class: "io.ballerina.stdlib.crypto.nativeimpl.Decode" +} external; + # Builds the RSA public key from the given modulus and exponent parameters. # ```ballerina # string modulus = "luZFdW1ynitztkWLC6xKegbRWxky..."; diff --git a/ballerina/tests/private_public_key_test.bal b/ballerina/tests/private_public_key_test.bal index d8b86539..8ac867fd 100644 --- a/ballerina/tests/private_public_key_test.bal +++ b/ballerina/tests/private_public_key_test.bal @@ -146,6 +146,12 @@ isolated function testParsePrivateKeyFromKeyPairFile() returns Error? { test:assertEquals(result["algorithm"], "RSA"); } +@test:Config {} +isolated function testParseEcPrivateKeyFromKeyFile() returns Error? { + PrivateKey result = check decodeEcPrivateKeyFromKeyFile(EC_PRIVATE_KEY_PATH); + test:assertEquals(result["algorithm"], "ECDSA"); +} + @test:Config {} isolated function testReadPrivateKeyFromNonExistingKeyFile() { PrivateKey|Error result = decodeRsaPrivateKeyFromKeyFile(INVALID_PRIVATE_KEY_PATH); @@ -236,6 +242,22 @@ isolated function testParsePublicKeyFromX509CertFile() returns Error? { test:assertEquals(signingAlgorithm, "SHA256withRSA"); } +@test:Config {} +isolated function testParseEcPublicKeyFromX509CertFile() returns Error? { + PublicKey publicKey = check decodeEcPublicKeyFromCertFile(EC_CERT_PATH); + test:assertEquals(publicKey["algorithm"], "EC"); + Certificate certificate = publicKey["certificate"]; + + string serial = (certificate["serial"]).toString(); + string issuer = certificate["issuer"]; + string subject = certificate["subject"]; + string signingAlgorithm = certificate["signingAlgorithm"]; + + test:assertEquals(serial, "813081972327485475"); + test:assertEquals(issuer, "CN=sigstore-intermediate,O=sigstore.dev"); + test:assertEquals(signingAlgorithm, "SHA384withECDSA"); +} + @test:Config {} isolated function testReadPublicKeyFromNonExistingCertFile() { PublicKey|Error result = decodeRsaPublicKeyFromCertFile(INVALID_PUBLIC_CERT_PATH); diff --git a/ballerina/tests/resources/ec-cert.crt b/ballerina/tests/resources/ec-cert.crt new file mode 100644 index 00000000..25f1d4ab --- /dev/null +++ b/ballerina/tests/resources/ec-cert.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIICzzCCAlWgAwIBAgIUJaBYA4gOhyDrjigfC0ilvvXakCMwCgYIKoZIzj0EAwMw +NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl +cm1lZGlhdGUwHhcNMjMxMjA4MDYxODI0WhcNMjMxMjA4MDYyODI0WjAAMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEyjXIb66skPFKbH8Bmjdg1DqZ6eOJV3za17Zs +EYpEgT2p33lzkiC2K9X39cATWrT1vd+PpzkRa6RrDobjrfzggqOCAXQwggFwMA4G +A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUQik2 +yPY3ziieNIhK2bADm1bRpmYwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y +ZD8wJAYDVR0RAQH/BBowGIEWZHdzbnNld3dhbmRpQGdtYWlsLmNvbTApBgorBgEE +AYO/MAEBBBtodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20wKwYKKwYBBAGDvzAB +CAQdDBtodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20wgYoGCisGAQQB1nkCBAIE +fAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynujgAAAYxIE8WD +AAAEAwBHMEUCIQCWhoJcbSAxit5NiPMrze0N0JdQC/dmVu/EpKkCiT4Y4gIgBazA +hpv2Oq49TvaYINlfO86ziKcTEAP9uh93JlWXHvowCgYIKoZIzj0EAwMDaAAwZQIw +Nq1+EWmcWn4IcHOYe0QJaikbSXxRn6wC16Kn6M/BMqgH1I8MmnY46MeQozY+FyCO +AjEAz0WV59exLU1hhMhtCOHG7WNyC2/vt+EMeUxM2tkNtQk/rHjEhorkwiqlgzAT +4jel +-----END CERTIFICATE----- \ No newline at end of file diff --git a/ballerina/tests/test_utils.bal b/ballerina/tests/test_utils.bal index 0f2cc0e8..30015648 100644 --- a/ballerina/tests/test_utils.bal +++ b/ballerina/tests/test_utils.bal @@ -21,6 +21,8 @@ const string KEY_PAIR_PATH = "tests/resources/keyPair.pem"; const string ENCRYPTED_PRIVATE_KEY_PATH = "tests/resources/encryptedPrivate.key"; const string PRIVATE_KEY_PATH = "tests/resources/private.key"; const string X509_PUBLIC_CERT_PATH = "tests/resources/public.crt"; +const string EC_CERT_PATH = "tests/resources/ec-cert.crt"; +const string EC_PRIVATE_KEY_PATH = "tests/resources/ec-key.pem"; const string INVALID_KEYSTORE_PATH = "tests/resources/cert/keyStore.p12.invalid"; const string INVALID_PRIVATE_KEY_PATH = "tests/resources/cert/private.key.invalid"; diff --git a/changelog.md b/changelog.md index 3182dadb..bb516ad6 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added +- [Introduce new APIs to decode private and public keys from files](https://github.com/ballerina-platform/ballerina-library/issues/5871) + +## [2.6.0] - 2023-12-08 + ### Added - [Introduce new APIs to interact with EC private keys and public keys](https://github.com/ballerina-platform/ballerina-library/issues/5821) diff --git a/docs/spec/spec.md b/docs/spec/spec.md index 42ed0851..6c3f829f 100644 --- a/docs/spec/spec.md +++ b/docs/spec/spec.md @@ -32,11 +32,15 @@ The conforming implementation of the specification is released and included in t * 3.4. [SHA384](#34-sha384) * 3.5. [SHA512](#35-sha512) 4. [Decode private/public key](#4-decode-private-public-keys) - * 4.1. [Decode Private key from PKCS12 file](#41-decode-private-key-from-pkcs12-file) + * 4.1. [Decode RSA Private key from PKCS12 file](#41-rsa-decode-private-key-from-pkcs12-file) * 4.2. [Decode RSA Private key using Private key and Password](#42-decode-rsa-private-key-using-private-key-and-password) * 4.3. [Decode RSA Public key from PKCS12 file](#43-decode-rsa-public-key-from-pkcs12-file) * 4.4. [Decode RSA Public key from the certificate file](#44-decode-rsa-public-key-from-the-certificate-file) - * 4.5. [Build RSA Public key from modulus and exponent parameters](#45-build-rsa-public-key-from-modulus-and-exponent-parameters) + * 4.5. [Decode EC Private key from PKCS12 file](#45-decode-ec-private-key-from-pkcs12-file) + * 4.6. [Decode EC Private key using Private key and Password](#46-decode-ec-private-key-using-private-key-and-password) + * 4.7. [Decode EC Public key from PKCS12 file](#47-decode-ec-public-key-from-pkcs12-file) + * 4.8. [Decode EC Public key from the certificate file](#48-decode-ec-public-key-from-the-certificate-file) + * 4.9. [Build RSA Public key from modulus and exponent parameters](#45-build-rsa-public-key-from-modulus-and-exponent-parameters) 5. [Encrypt-Decrypt](#5-encrypt-decrypt) * 5.1. [Encryption](#51-encryption) * 5.1.1. [RSA](#511-rsa) @@ -194,9 +198,9 @@ byte[] hmac = check crypto:hmacSha512(data, key); The `crypto` library supports decoding the RSA private key from a `.p12` file and a key file in the `PEM` format. Also, it supports decoding a public key from a `.p12` file and a certificate file in the `X509` format. Additionally, this supports building an RSA public key with the modulus and exponent parameters. -### 4.1. [Decode Private key from PKCS12 file](#41-decode-private-key-from-pkcs12-file) +### 4.1. [Decode RSA Private key from PKCS12 file](#41-rsa-decode-private-key-from-pkcs12-file) -This API can be used to decode the private key from the given PKCS#12 file. +This API can be used to decode the RSA private key from the given PKCS#12 file. ```ballerina crypto:KeyStore keyStore = { @@ -236,7 +240,49 @@ string certFile = "/path/to/public.cert"; crypto:PublicKey publicKey = check crypto:decodeRsaPublicKeyFromCertFile(certFile); ``` -### 4.5. [Build RSA Public key from modulus and exponent parameters](#45-build-rsa-public-key-from-modulus-and-exponent-parameters) +### 4.5. [Decode EC Private key from PKCS12 file](#45-decode-ec-private-key-from-pkcs12-file) + +This API can be used to decode the EC private key from the given PKCS#12 file. + +```ballerina +crypto:KeyStore keyStore = { + path: "/path/to/keyStore.p12", + password: "keyStorePassword" +}; +crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyStore(keyStore, "keyAlias", "keyPassword"); +``` + +### 4.6. [Decode EC Private key using Private key and Password](#46-decode-ec-private-key-using-private-key-and-password) + +This API can be used to decode the EC private key from the given private key and private key password. + +```ballerina +string keyFile = "/path/to/private.key"; +crypto:PrivateKey privateKey = check crypto:decodeEcPrivateKeyFromKeyFile(keyFile, "keyPassword"); +``` + +### 4.7. [Decode EC Public key from PKCS12 file](#47-decode-ec-public-key-from-pkcs12-file) + +This API can be used to decode the RSA public key from the given PKCS#12 archive file. + +```ballerina +crypto:TrustStore trustStore = { + path: "/path/tp/truststore.p12", + password: "truststorePassword" +}; +crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromTrustStore(trustStore, "keyAlias"); +``` + +### 4.8. [Decode EC Public key from the certificate file](#48-decode-ec-public-key-from-the-certificate-file) + +This API can be used to decode the EC public key from the given public certificate file. + +```ballerina +string certFile = "/path/to/public.cert"; +crypto:PublicKey publicKey = check crypto:decodeEcPublicKeyFromCertFile(certFile); +``` + +### 4.9. [Build RSA Public key from modulus and exponent parameters](#49-build-rsa-public-key-from-modulus-and-exponent-parameters) This API can be used to build the RSA public key from the given modulus and exponent parameters. diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java index 059a2905..a4557b32 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java @@ -119,6 +119,22 @@ private static Object getPrivateKey(BMap keyStoreRecord, BStri } public static Object decodeRsaPrivateKeyFromKeyFile(BString keyFilePath, Object keyPassword) { + Object decodedPrivateKey = getPrivateKey(keyFilePath, keyPassword); + if (decodedPrivateKey instanceof PrivateKey privateKey) { + return buildRsPrivateKeyRecord(privateKey); + } + return decodedPrivateKey; + } + + public static Object decodeEcPrivateKeyFromKeyFile(BString keyFilePath, Object keyPassword) { + Object decodedPrivateKey = getPrivateKey(keyFilePath, keyPassword); + if (decodedPrivateKey instanceof PrivateKey privateKey) { + return buildEcPrivateKeyRecord(privateKey); + } + return decodedPrivateKey; + } + + private static Object getPrivateKey(BString keyFilePath, Object keyPassword) { Security.addProvider(new BouncyCastleProvider()); File privateKeyFile = new File(keyFilePath.getValue()); try (PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile, StandardCharsets.UTF_8))) { @@ -151,7 +167,7 @@ public static Object decodeRsaPrivateKeyFromKeyFile(BString keyFilePath, Object keyFilePath.getValue()); } PrivateKey privateKey = converter.getPrivateKey(privateKeyInfo); - return buildRsPrivateKeyRecord(privateKey); + return privateKey; } catch (FileNotFoundException e) { return CryptoUtils.createError("Key file not found at: " + privateKeyFile.getAbsoluteFile()); } catch (PKCSException | IOException e) { @@ -177,7 +193,7 @@ private static Object getPrivateKeyRecord(PrivateKey privateKey) { } private static Object buildEcPrivateKeyRecord(PrivateKey privateKey) { - if (privateKey.getAlgorithm().equals(Constants.EC_ALGORITHM)) { + if (privateKey.getAlgorithm().startsWith(Constants.EC_ALGORITHM)) { return getPrivateKeyRecord(privateKey); } return CryptoUtils.createError("Not a valid EC key"); @@ -235,6 +251,19 @@ public static Object decodeRsaPublicKeyFromCertFile(BString certFilePath) { } } + public static Object decodeEcPublicKeyFromCertFile(BString certFilePath) { + File certFile = new File(certFilePath.getValue()); + try (FileInputStream fileInputStream = new FileInputStream(certFile)) { + CertificateFactory certificateFactory = CertificateFactory.getInstance(Constants.CERTIFICATE_TYPE_X509); + X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(fileInputStream); + return buildEcPublicKeyRecord(certificate); + } catch (FileNotFoundException e) { + return CryptoUtils.createError("Certificate file not found at: " + certFile.getAbsolutePath()); + } catch (CertificateException | IOException e) { + return CryptoUtils.createError("Unable to do public key operations: " + e.getMessage()); + } + } + private static Object buildRsaPublicKeyRecord(Certificate certificate) { BMap certificateBMap = enrichPublicKeyInfo(certificate); PublicKey publicKey = certificate.getPublicKey(); From cd0e6425b5965d06e2848946761c75b4b17d53e7 Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 14:52:12 +0530 Subject: [PATCH 2/6] Add key file --- ballerina/tests/resources/ec-key.pem | 8 ++++++++ docs/spec/spec.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 ballerina/tests/resources/ec-key.pem diff --git a/ballerina/tests/resources/ec-key.pem b/ballerina/tests/resources/ec-key.pem new file mode 100644 index 00000000..53014418 --- /dev/null +++ b/ballerina/tests/resources/ec-key.pem @@ -0,0 +1,8 @@ +Bag Attributes + friendlyName: ec-keypair + localKeyID: 54 69 6D 65 20 31 37 30 31 30 37 39 30 34 34 33 30 32 +Key Attributes: +-----BEGIN PRIVATE KEY----- +MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCbdsjMze7hLWRnyp8P +aBXFBeUojC+lv4HGtvIJAJ8HIA== +-----END PRIVATE KEY----- diff --git a/docs/spec/spec.md b/docs/spec/spec.md index 6c3f829f..2f06b776 100644 --- a/docs/spec/spec.md +++ b/docs/spec/spec.md @@ -40,7 +40,7 @@ The conforming implementation of the specification is released and included in t * 4.6. [Decode EC Private key using Private key and Password](#46-decode-ec-private-key-using-private-key-and-password) * 4.7. [Decode EC Public key from PKCS12 file](#47-decode-ec-public-key-from-pkcs12-file) * 4.8. [Decode EC Public key from the certificate file](#48-decode-ec-public-key-from-the-certificate-file) - * 4.9. [Build RSA Public key from modulus and exponent parameters](#45-build-rsa-public-key-from-modulus-and-exponent-parameters) + * 4.9. [Build RSA Public key from modulus and exponent parameters](#49-build-rsa-public-key-from-modulus-and-exponent-parameters) 5. [Encrypt-Decrypt](#5-encrypt-decrypt) * 5.1. [Encryption](#51-encryption) * 5.1.1. [RSA](#511-rsa) From 9b7ea6a391b2030bbe89994ed82b237d2ba3baec Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 14:55:06 +0530 Subject: [PATCH 3/6] Update code owners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d1fa4741..9535c35e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,4 +4,4 @@ # See: https://help.github.com/articles/about-codeowners/ # These owners will be the default owners for everything in the repo. -* @shafreenAnfar @Bhashinee +* @shafreenAnfar @Bhashinee @MohamedSabthar From 7d49cb160f219aa4aa4f0388fd020fef0f5ec873 Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 15:03:07 +0530 Subject: [PATCH 4/6] [Automated] Update the native jar versions --- ballerina/Ballerina.toml | 6 +++--- ballerina/Dependencies.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 64c530d3..f0febdbe 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -1,7 +1,7 @@ [package] org = "ballerina" name = "crypto" -version = "2.6.0" +version = "2.6.1" authors = ["Ballerina"] keywords = ["security", "hash", "hmac", "sign", "encrypt", "decrypt", "private key", "public key"] repository = "https://github.com/ballerina-platform/module-ballerina-crypto" @@ -15,8 +15,8 @@ graalvmCompatible = true [[platform.java17.dependency]] groupId = "io.ballerina.stdlib" artifactId = "crypto-native" -version = "2.6.0" -path = "../native/build/libs/crypto-native-2.6.0.jar" +version = "2.6.1" +path = "../native/build/libs/crypto-native-2.6.1-SNAPSHOT.jar" [[platform.java17.dependency]] groupId = "org.bouncycastle" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index c0151c26..212e2d02 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -10,7 +10,7 @@ distribution-version = "2201.8.0" [[package]] org = "ballerina" name = "crypto" -version = "2.6.0" +version = "2.6.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "test"}, From 6c1e44ca53784276575a1ec9bd0c7be815a52d97 Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 15:08:19 +0530 Subject: [PATCH 5/6] Add negative tests --- ballerina/tests/private_public_key_test.bal | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ballerina/tests/private_public_key_test.bal b/ballerina/tests/private_public_key_test.bal index 8ac867fd..e664be1f 100644 --- a/ballerina/tests/private_public_key_test.bal +++ b/ballerina/tests/private_public_key_test.bal @@ -152,6 +152,26 @@ isolated function testParseEcPrivateKeyFromKeyFile() returns Error? { test:assertEquals(result["algorithm"], "ECDSA"); } +@test:Config {} +isolated function testParseErrorEcPrivateKeyFromKeyFile() returns Error? { + PrivateKey|Error result = decodeEcPrivateKeyFromKeyFile(PRIVATE_KEY_PATH); + if result is Error { + test:assertEquals(result.message(), "Not a valid EC key"); + } else { + test:assertFail("Expected error not found"); + } +} + +@test:Config {} +isolated function testParseErrorEcPublicKeyFromKeyFile() returns Error? { + PublicKey|Error result = decodeEcPublicKeyFromCertFile(PRIVATE_KEY_PATH); + if result is Error { + test:assertEquals(result.message(), "Unable to do public key operations: signed fields invalid"); + } else { + test:assertFail("Expected error not found"); + } +} + @test:Config {} isolated function testReadPrivateKeyFromNonExistingKeyFile() { PrivateKey|Error result = decodeRsaPrivateKeyFromKeyFile(INVALID_PRIVATE_KEY_PATH); From 12b41095a7a9ea865148234a4df8f62fc759f4ca Mon Sep 17 00:00:00 2001 From: bhashinee Date: Mon, 11 Dec 2023 17:24:41 +0530 Subject: [PATCH 6/6] Address review suggestions --- ballerina/tests/private_public_key_test.bal | 48 +++++++++---------- .../stdlib/crypto/nativeimpl/Decode.java | 3 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/ballerina/tests/private_public_key_test.bal b/ballerina/tests/private_public_key_test.bal index e664be1f..c0ed0a93 100644 --- a/ballerina/tests/private_public_key_test.bal +++ b/ballerina/tests/private_public_key_test.bal @@ -23,7 +23,7 @@ isolated function testParseEncryptedPrivateKeyFromP12() returns Error? { password: "ballerina" }; PrivateKey result = check decodeRsaPrivateKeyFromKeyStore(keyStore, "ballerina", "ballerina"); - test:assertEquals(result["algorithm"], "RSA"); + test:assertEquals(result.algorithm, "RSA"); } @test:Config {} @@ -85,13 +85,13 @@ isolated function testReadPrivateKeyFromP12WithInvalidKeyPassword() { @test:Config {} isolated function testParsePrivateKeyFromKeyFile() returns Error? { PrivateKey result = check decodeRsaPrivateKeyFromKeyFile(PRIVATE_KEY_PATH); - test:assertEquals(result["algorithm"], "RSA"); + test:assertEquals(result.algorithm, "RSA"); } @test:Config {} isolated function testParseEncryptedPrivateKeyFromKeyFile() returns Error? { PrivateKey result = check decodeRsaPrivateKeyFromKeyFile(ENCRYPTED_PRIVATE_KEY_PATH, "ballerina"); - test:assertEquals(result["algorithm"], "RSA"); + test:assertEquals(result.algorithm, "RSA"); } @test:Config {} @@ -117,7 +117,7 @@ isolated function testParseEncryptedPrivateKeyFromKeyFileWithNoPassword() { @test:Config {} isolated function testParseEncryptedPrivateKeyFromKeyPairFile() returns Error? { PrivateKey result = check decodeRsaPrivateKeyFromKeyFile(ENCRYPTED_KEY_PAIR_PATH, "ballerina"); - test:assertEquals(result["algorithm"], "RSA"); + test:assertEquals(result.algorithm, "RSA"); } @test:Config {} @@ -143,13 +143,13 @@ isolated function testParseEncryptedPrivateKeyFromKeyPairFileWithNoPassword() { @test:Config {} isolated function testParsePrivateKeyFromKeyPairFile() returns Error? { PrivateKey result = check decodeRsaPrivateKeyFromKeyFile(KEY_PAIR_PATH); - test:assertEquals(result["algorithm"], "RSA"); + test:assertEquals(result.algorithm, "RSA"); } @test:Config {} isolated function testParseEcPrivateKeyFromKeyFile() returns Error? { PrivateKey result = check decodeEcPrivateKeyFromKeyFile(EC_PRIVATE_KEY_PATH); - test:assertEquals(result["algorithm"], "ECDSA"); + test:assertEquals(result.algorithm, "ECDSA"); } @test:Config {} @@ -189,13 +189,13 @@ isolated function testParsePublicKeyFromP12() returns Error? { password: "ballerina" }; PublicKey publicKey = check decodeRsaPublicKeyFromTrustStore(trustStore, "ballerina"); - test:assertEquals(publicKey["algorithm"], "RSA"); - Certificate certificate = publicKey["certificate"]; + test:assertEquals(publicKey.algorithm, "RSA"); + Certificate certificate = publicKey.certificate; - string serial = (certificate["serial"]).toString(); - string issuer = certificate["issuer"]; - string subject = certificate["subject"]; - string signingAlgorithm = certificate["signingAlgorithm"]; + string serial = (certificate.serial).toString(); + string issuer = certificate.issuer; + string subject = certificate.subject; + string signingAlgorithm = certificate.signingAlgorithm; test:assertEquals(serial, "2097012467"); test:assertEquals(issuer, "CN=localhost,OU=WSO2,O=WSO2,L=Mountain View,ST=CA,C=US"); @@ -248,13 +248,13 @@ isolated function testReadPublicKeyFromP12WithInvalidAlias() { @test:Config {} isolated function testParsePublicKeyFromX509CertFile() returns Error? { PublicKey publicKey = check decodeRsaPublicKeyFromCertFile(X509_PUBLIC_CERT_PATH); - test:assertEquals(publicKey["algorithm"], "RSA"); - Certificate certificate = publicKey["certificate"]; + test:assertEquals(publicKey.algorithm, "RSA"); + Certificate certificate = publicKey.certificate; - string serial = (certificate["serial"]).toString(); - string issuer = certificate["issuer"]; - string subject = certificate["subject"]; - string signingAlgorithm = certificate["signingAlgorithm"]; + string serial = (certificate.serial).toString(); + string issuer = certificate.issuer; + string subject = certificate.subject; + string signingAlgorithm = certificate.signingAlgorithm; test:assertEquals(serial, "2097012467"); test:assertEquals(issuer, "CN=localhost,OU=WSO2,O=WSO2,L=Mountain View,ST=CA,C=US"); @@ -265,13 +265,13 @@ isolated function testParsePublicKeyFromX509CertFile() returns Error? { @test:Config {} isolated function testParseEcPublicKeyFromX509CertFile() returns Error? { PublicKey publicKey = check decodeEcPublicKeyFromCertFile(EC_CERT_PATH); - test:assertEquals(publicKey["algorithm"], "EC"); - Certificate certificate = publicKey["certificate"]; + test:assertEquals(publicKey.algorithm, "EC"); + Certificate certificate = publicKey.certificate; - string serial = (certificate["serial"]).toString(); - string issuer = certificate["issuer"]; - string subject = certificate["subject"]; - string signingAlgorithm = certificate["signingAlgorithm"]; + string serial = (certificate.serial).toString(); + string issuer = certificate.issuer; + string subject = certificate.subject; + string signingAlgorithm = certificate.signingAlgorithm; test:assertEquals(serial, "813081972327485475"); test:assertEquals(issuer, "CN=sigstore-intermediate,O=sigstore.dev"); diff --git a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java index a4557b32..41d4dcc2 100644 --- a/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java +++ b/native/src/main/java/io/ballerina/stdlib/crypto/nativeimpl/Decode.java @@ -166,8 +166,7 @@ private static Object getPrivateKey(BString keyFilePath, Object keyPassword) { return CryptoUtils.createError("Failed to parse private key information from: " + keyFilePath.getValue()); } - PrivateKey privateKey = converter.getPrivateKey(privateKeyInfo); - return privateKey; + return converter.getPrivateKey(privateKeyInfo); } catch (FileNotFoundException e) { return CryptoUtils.createError("Key file not found at: " + privateKeyFile.getAbsoluteFile()); } catch (PKCSException | IOException e) {