From 7ba4ab5da8c8f7ec9ed19334ec8dce4f135a5caf Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 7 Oct 2022 14:38:37 -0300 Subject: [PATCH 1/9] Add public key data type --- .../asymmetric/AsymmetricCipher.java | 116 +++++-- .../asymmetric/AsymmetricSigner.java | 194 +++++++---- .../commons/AsymmetricCipherObject.java | 12 +- .../commons/AsymmetricSignerObject.java | 5 + .../main/java/com/genexus/JWT/JWTCreator.java | 104 +++++- .../com/genexus/JWT/utils/JWTAlgorithm.java | 41 ++- .../java/com/genexus/commons/JWTOptions.java | 17 +- .../java/com/genexus/dsig/XmlDSigSigner.java | 273 +++++++++++++-- .../commons/Certificate.java | 2 +- .../securityapicommons/commons/Error.java | 7 + .../securityapicommons/commons/Key.java | 16 +- .../commons/PrivateKey.java | 5 +- .../securityapicommons/commons/PublicKey.java | 188 +++++++++++ .../keys/CertificateX509.java | 288 ++++------------ .../keys/PrivateKeyManager.java | 313 +++++++----------- 15 files changed, 1007 insertions(+), 574 deletions(-) create mode 100644 SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PublicKey.java diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricCipher.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricCipher.java index 015b6ac..958122e 100644 --- a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricCipher.java +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricCipher.java @@ -2,6 +2,7 @@ import java.io.UnsupportedEncodingException; +import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.BufferedAsymmetricBlockCipher; import org.bouncycastle.crypto.Digest; @@ -18,10 +19,13 @@ import com.genexus.cryptography.commons.AsymmetricCipherObject; import com.genexus.cryptography.hash.Hashing; import com.genexus.cryptography.hash.utils.HashAlgorithm; +import com.genexus.securityapicommons.commons.Certificate; import com.genexus.securityapicommons.commons.Key; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.config.EncodingUtil; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; +import com.genexus.securityapicommons.utils.SecurityUtils; /** * @author sgrampone @@ -41,37 +45,106 @@ public AsymmetricCipher() { @Override public String doEncrypt_WithPrivateKey(String hashAlgorithm, String asymmetricEncryptionPadding, PrivateKeyManager key, String plainText) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("plainText", plainText, this.error); + SecurityUtils.validateObjectInput("key", key, this.error); if (this.hasError()) { return ""; } - return doEncryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, true, plainText); + + /******* INPUT VERIFICATION - END *******/ + + return doEncryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, true, plainText, false); } @Override - public String doEncrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, CertificateX509 certificate, String plainText) { + public String doEncrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, PublicKey key, String plainText) { + + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("plainText", plainText, this.error); + SecurityUtils.validateObjectInput("key", key, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + return doEncryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, false, plainText, true); + } + + @Override + public String doEncrypt_WithCertificate(String hashAlgorithm, String asymmetricEncryptionPadding, Certificate certificate, String plainText) { + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("plainText", plainText, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); if (this.hasError()) { return ""; } - return doEncryptInternal(hashAlgorithm, asymmetricEncryptionPadding, certificate, false, plainText); + + /******* INPUT VERIFICATION - END *******/ + + return doEncryptInternal(hashAlgorithm, asymmetricEncryptionPadding, certificate, false, plainText, false); } + @Override public String doDecrypt_WithPrivateKey(String hashAlgorithm, String asymmetricEncryptionPadding, PrivateKeyManager key, String encryptedInput) { - + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("encryptedInput", encryptedInput, this.error); + SecurityUtils.validateObjectInput("key", key, this.error); if (this.hasError()) { return ""; } - return doDecryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, true, encryptedInput); + + /******* INPUT VERIFICATION - END *******/ + + return doDecryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, true, encryptedInput, false); } @Override - public String doDecrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, CertificateX509 certificate, String encryptedInput) { + public String doDecrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, PublicKey key, String encryptedInput) { + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("encryptedInput", encryptedInput, this.error); + SecurityUtils.validateObjectInput("key", key, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + return doDecryptInternal(hashAlgorithm, asymmetricEncryptionPadding, key, false, encryptedInput, true); + } + + @Override + public String doDecrypt_WithCertificate(String hashAlgorithm, String asymmetricEncryptionPadding, Certificate certificate, String encryptedInput) { + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("hashAlgorithm", hashAlgorithm, this.error); + SecurityUtils.validateStringInput("asymmetricEncryptionPadding", asymmetricEncryptionPadding, this.error); + SecurityUtils.validateStringInput("encryptedInput", encryptedInput, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); if (this.hasError()) { return ""; } - return doDecryptInternal(hashAlgorithm, asymmetricEncryptionPadding, certificate, false, encryptedInput); + + /******* INPUT VERIFICATION - END *******/ + + return doDecryptInternal(hashAlgorithm, asymmetricEncryptionPadding, certificate, false, encryptedInput, false); } /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ @@ -96,9 +169,8 @@ public String doDecrypt_WithPublicKey(String hashAlgorithm, String asymmetricEnc * @return String Base64 encrypted plainText text */ private String doEncryptInternal(String hashAlgorithm, String asymmetricEncryptionPadding, Key key, boolean isPrivate, - String plainText) { + String plainText, boolean isPublicKey) { error.cleanError(); - HashAlgorithm hash = HashAlgorithm.getHashAlgorithm(hashAlgorithm, this.error); AsymmetricEncryptionPadding padding = AsymmetricEncryptionPadding .getAsymmetricEncryptionPadding(asymmetricEncryptionPadding, this.error); @@ -114,21 +186,21 @@ private String doEncryptInternal(String hashAlgorithm, String asymmetricEncrypti this.error = keyMan.getError(); return ""; } - asymmetricEncryptionAlgorithm = keyMan.getPrivateKeyAlgorithm(); + asymmetricEncryptionAlgorithm = keyMan.getAlgorithm(); - asymKey = keyMan.getPrivateKeyParameterForEncryption(); + asymKey = keyMan.getAsymmetricKeyParameter(); if (keyMan.hasError()) { this.error = keyMan.getError(); return ""; } } else { - CertificateX509 cert = (CertificateX509) key; - if (!cert.Inicialized() || cert.hasError()) { + PublicKey cert = isPublicKey ? (PublicKey)key: (CertificateX509) key; + if (cert.hasError()) { this.error = cert.getError(); return ""; } - asymmetricEncryptionAlgorithm = cert.getPublicKeyAlgorithm(); - asymKey = cert.getPublicKeyParameterForEncryption(); + asymmetricEncryptionAlgorithm = cert.getAlgorithm(); + asymKey = cert.getAsymmetricKeyParameter(); if (cert.hasError()) { this.error = cert.getError(); return ""; @@ -167,7 +239,7 @@ private String doEncryptInternal(String hashAlgorithm, String asymmetricEncrypti * @return String UTF-8 decypted encryptedInput text */ private String doDecryptInternal(String hashAlgorithm, String asymmetricEncryptionPadding, Key key, boolean isPrivate, - String encryptedInput) { + String encryptedInput, boolean isPublicKey) { this.error.cleanError(); HashAlgorithm hash = HashAlgorithm.getHashAlgorithm(hashAlgorithm, this.error); AsymmetricEncryptionPadding padding = AsymmetricEncryptionPadding @@ -185,21 +257,21 @@ private String doDecryptInternal(String hashAlgorithm, String asymmetricEncrypti this.error = keyMan.getError(); return ""; } - asymmetricEncryptionAlgorithm = keyMan.getPrivateKeyAlgorithm(); + asymmetricEncryptionAlgorithm = keyMan.getAlgorithm(); - asymKey = keyMan.getPrivateKeyParameterForEncryption(); + asymKey = keyMan.getAsymmetricKeyParameter(); if (keyMan.hasError()) { this.error = keyMan.getError(); return ""; } } else { - CertificateX509 cert = (CertificateX509) key; - if (!cert.Inicialized() || cert.hasError()) { + PublicKey cert = isPublicKey ? (PublicKey) key: (CertificateX509) key; + if (cert.hasError()) { this.error = cert.getError(); return ""; } - asymmetricEncryptionAlgorithm = cert.getPublicKeyAlgorithm(); - asymKey = cert.getPublicKeyParameterForEncryption(); + asymmetricEncryptionAlgorithm = cert.getAlgorithm(); + asymKey = cert.getAsymmetricKeyParameter(); if (cert.hasError()) { this.error = cert.getError(); return ""; diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricSigner.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricSigner.java index b154adb..4453a5c 100644 --- a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricSigner.java +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/AsymmetricSigner.java @@ -12,8 +12,9 @@ import com.genexus.cryptography.commons.AsymmetricSignerObject; import com.genexus.cryptography.hash.Hashing; import com.genexus.cryptography.hash.utils.HashAlgorithm; -import com.genexus.securityapicommons.commons.Certificate; +import com.genexus.securityapicommons.commons.Key; import com.genexus.securityapicommons.commons.PrivateKey; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.config.EncodingUtil; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; @@ -29,17 +30,20 @@ public AsymmetricSigner() { } /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ - + @Override public String doSign(PrivateKeyManager key, String hashAlgorithm, String plainText) { this.error.cleanError(); - - /*******INPUT VERIFICATION - BEGIN*******/ + + /******* INPUT VERIFICATION - BEGIN *******/ SecurityUtils.validateObjectInput("key", key, this.error); SecurityUtils.validateStringInput("hashAlgorithm", hashAlgorithm, this.error); SecurityUtils.validateStringInput("plainText", plainText, this.error); - if(this.hasError()) { return "";}; - /*******INPUT VERIFICATION - END*******/ + if (this.hasError()) { + return ""; + } + ; + /******* INPUT VERIFICATION - END *******/ EncodingUtil eu = new EncodingUtil(); byte[] inputText = eu.getBytes(plainText); @@ -48,11 +52,9 @@ public String doSign(PrivateKeyManager key, String hashAlgorithm, String plainTe return ""; } String result = ""; - try(InputStream inputStream = new ByteArrayInputStream(inputText)) - { + try (InputStream inputStream = new ByteArrayInputStream(inputText)) { result = sign(key, hashAlgorithm, inputStream); - }catch(Exception e) - { + } catch (Exception e) { error.setError("AS001", e.getMessage()); } return result; @@ -62,23 +64,23 @@ public String doSign(PrivateKeyManager key, String hashAlgorithm, String plainTe public String doSignFile(PrivateKeyManager key, String hashAlgorithm, String path) { this.error.cleanError(); - /*******INPUT VERIFICATION - BEGIN*******/ + /******* INPUT VERIFICATION - BEGIN *******/ SecurityUtils.validateObjectInput("key", key, this.error); SecurityUtils.validateStringInput("hashAlgorithm", hashAlgorithm, this.error); - SecurityUtils.validateStringInput("path", path, this.error); - if(this.hasError()) { return "";} - /*******INPUT VERIFICATION - END*******/ - + SecurityUtils.validateStringInput("path", path, this.error); + if (this.hasError()) { + return ""; + } + /******* INPUT VERIFICATION - END *******/ + String result = ""; - try(InputStream input = SecurityUtils.getFileStream(path, this.error)) - { + try (InputStream input = SecurityUtils.getFileStream(path, this.error)) { if (this.hasError()) { return ""; } - + result = sign(key, hashAlgorithm, input); - }catch(Exception e) - { + } catch (Exception e) { error.setError("AS002", e.getMessage()); } return result; @@ -87,14 +89,16 @@ public String doSignFile(PrivateKeyManager key, String hashAlgorithm, String pat @Override public boolean doVerify(CertificateX509 cert, String plainText, String signature) { this.error.cleanError(); - - /*******INPUT VERIFICATION - BEGIN*******/ + + /******* INPUT VERIFICATION - BEGIN *******/ SecurityUtils.validateObjectInput("cert", cert, this.error); SecurityUtils.validateStringInput("plainText", plainText, this.error); - SecurityUtils.validateStringInput("signature", signature, this.error); - if(this.hasError()) { return false;} - /*******INPUT VERIFICATION - END*******/ - + SecurityUtils.validateStringInput("signature", signature, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + EncodingUtil eu = new EncodingUtil(); byte[] inputText = eu.getBytes(plainText); if (eu.hasError()) { @@ -102,12 +106,39 @@ public boolean doVerify(CertificateX509 cert, String plainText, String signature return false; } boolean result = false; - try(InputStream inputStream = new ByteArrayInputStream(inputText)) - { - result = verify(cert, inputStream, signature); - }catch(Exception e) - { - error.setError("AS003", e.getMessage() ); + try (InputStream inputStream = new ByteArrayInputStream(inputText)) { + result = verify(cert, inputStream, signature, null); + } catch (Exception e) { + error.setError("AS003", e.getMessage()); + } + return result; + } + + @Override + public boolean doVerifyWithPublicKey(PublicKey key, String plainText, String signature, String hash) { + this.error.cleanError(); + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("key", key, this.error); + SecurityUtils.validateStringInput("plainText", plainText, this.error); + SecurityUtils.validateStringInput("signature", signature, this.error); + SecurityUtils.validateStringInput("hashAlgorithm", hash, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + + EncodingUtil eu = new EncodingUtil(); + byte[] inputText = eu.getBytes(plainText); + if (eu.hasError()) { + this.error = eu.getError(); + return false; + } + boolean result = false; + try (InputStream inputStream = new ByteArrayInputStream(inputText)) { + result = verify(key, inputStream, signature, hash); + } catch (Exception e) { + error.setError("AS003", e.getMessage()); } return result; } @@ -116,29 +147,55 @@ public boolean doVerify(CertificateX509 cert, String plainText, String signature public boolean doVerifyFile(CertificateX509 cert, String path, String signature) { this.error.cleanError(); - /*******INPUT VERIFICATION - BEGIN*******/ + /******* INPUT VERIFICATION - BEGIN *******/ SecurityUtils.validateObjectInput("cert", cert, this.error); SecurityUtils.validateStringInput("path", path, this.error); - SecurityUtils.validateStringInput("signature", signature, this.error); - if(this.hasError()) { return false;} - /*******INPUT VERIFICATION - END*******/ - + SecurityUtils.validateStringInput("signature", signature, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + boolean result = false; - try(InputStream input = SecurityUtils.getFileStream(path, this.error)) - { + try (InputStream input = SecurityUtils.getFileStream(path, this.error)) { if (this.hasError()) { return false; } - result = verify(cert, input, signature); - }catch(Exception e) - { + result = verify(cert, input, signature, null); + } catch (Exception e) { + error.setError("AS004", e.getMessage()); + } + return result; + } + + @Override + public boolean doVerifyFileWithPublicKey(PublicKey key, String path, String signature, String hash) { + this.error.cleanError(); + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("key", key, this.error); + SecurityUtils.validateStringInput("path", path, this.error); + SecurityUtils.validateStringInput("signature", signature, this.error); + SecurityUtils.validateStringInput("hashAlgorithm", hash, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + + boolean result = false; + try (InputStream input = SecurityUtils.getFileStream(path, this.error)) { + if (this.hasError()) { + return false; + } + result = verify(key, input, signature, hash); + } catch (Exception e) { error.setError("AS004", e.getMessage()); } return result; } /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ - + private String sign(PrivateKey key, String hashAlgorithm, InputStream input) { PrivateKeyManager keyMan = (PrivateKeyManager) key; if (keyMan.hasError()) { @@ -146,13 +203,16 @@ private String sign(PrivateKey key, String hashAlgorithm, InputStream input) { return ""; } AsymmetricSigningAlgorithm asymmetricSigningAlgorithm = AsymmetricSigningAlgorithm - .getAsymmetricSigningAlgorithm(keyMan.getPrivateKeyAlgorithm(), this.error); - if (this.hasError()) return ""; + .getAsymmetricSigningAlgorithm(keyMan.getAlgorithm(), this.error); + if (this.hasError()) + return ""; Signer signer = AsymmetricSigningAlgorithm.getSigner(asymmetricSigningAlgorithm, getHash(hashAlgorithm), this.error); - if (this.hasError()) return ""; - setUpSigner(signer, input, keyMan.getPrivateKeyParameterForSigning(), true); - if (this.hasError()) return ""; + if (this.hasError()) + return ""; + setUpSigner(signer, input, keyMan.getAsymmetricKeyParameter(), true); + if (this.hasError()) + return ""; byte[] outputBytes = null; try { outputBytes = signer.generateSignature(); @@ -170,26 +230,40 @@ private String sign(PrivateKey key, String hashAlgorithm, InputStream input) { return result; } - private boolean verify(Certificate certificate, InputStream input, String signature) { - CertificateX509 cert = (CertificateX509) certificate; - if (!cert.Inicialized() || cert.hasError()) { + private boolean verify(Key key, InputStream input, String signature, String hash) { + PublicKey cert = null; + boolean isKey = false; + if (hash == null) { + cert = (CertificateX509) key; + } else { + cert = (PublicKey) key; + isKey = true; + } + if (cert.hasError()) { this.error = cert.getError(); return false; } String hashAlgorithm = ""; - if (SecurityUtils.compareStrings(cert.getPublicKeyHash(), "ECDSA")) { - hashAlgorithm = "SHA1"; + if (isKey) { + hashAlgorithm = hash; } else { - hashAlgorithm = cert.getPublicKeyHash(); + if (SecurityUtils.compareStrings(((CertificateX509) cert).getPublicKeyHash(), "ECDSA")) { + hashAlgorithm = "SHA1"; + } else { + hashAlgorithm = ((CertificateX509) cert).getPublicKeyHash(); + } } AsymmetricSigningAlgorithm asymmetricSigningAlgorithm = AsymmetricSigningAlgorithm - .getAsymmetricSigningAlgorithm(cert.getPublicKeyAlgorithm(), this.error); - if (this.hasError()) return false; + .getAsymmetricSigningAlgorithm(cert.getAlgorithm(), this.error); + if (this.hasError()) + return false; Signer signer = AsymmetricSigningAlgorithm.getSigner(asymmetricSigningAlgorithm, getHash(hashAlgorithm), this.error); - if (this.hasError()) return false; - setUpSigner(signer, input, cert.getPublicKeyParameterForSigning(), false); - if (this.hasError()) return false; + if (this.hasError()) + return false; + setUpSigner(signer, input, cert.getAsymmetricKeyParameter(), false); + if (this.hasError()) + return false; byte[] signatureBytes = null; try { signatureBytes = Base64.decode(signature); @@ -227,7 +301,7 @@ private void setUpSigner(Signer signer, InputStream input, AsymmetricKeyParamete return; } } - + private Digest getHash(String hashAlgorithm) { HashAlgorithm hash = HashAlgorithm.getHashAlgorithm(hashAlgorithm, this.error); if (this.hasError()) { diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricCipherObject.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricCipherObject.java index 69c5e5d..f8895bb 100644 --- a/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricCipherObject.java +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricCipherObject.java @@ -1,5 +1,7 @@ package com.genexus.cryptography.commons; +import com.genexus.securityapicommons.commons.Certificate; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.commons.SecurityAPIObject; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; @@ -21,12 +23,18 @@ public abstract String doEncrypt_WithPrivateKey(String hashAlgorithm, String asy PrivateKeyManager key, String plainText); public abstract String doEncrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, - CertificateX509 certificate, String plainText); + PublicKey key, String plainText); + + public abstract String doEncrypt_WithCertificate(String hashAlgorithm, String asymmetricEncryptionPadding, + Certificate certificate, String plainText); public abstract String doDecrypt_WithPrivateKey(String hashAlgorithm, String asymmetricEncryptionPadding, PrivateKeyManager key, String encryptedInput); public abstract String doDecrypt_WithPublicKey(String hashAlgorithm, String asymmetricEncryptionPadding, - CertificateX509 certificate, String encryptedInput); + PublicKey key, String encryptedInput); + + public abstract String doDecrypt_WithCertificate(String hashAlgorithm, String asymmetricEncryptionPadding, + Certificate certificate, String encryptedInput); } diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricSignerObject.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricSignerObject.java index de16f1b..a5bf1a7 100644 --- a/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricSignerObject.java +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/AsymmetricSignerObject.java @@ -1,5 +1,6 @@ package com.genexus.cryptography.commons; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.commons.SecurityAPIObject; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; @@ -50,6 +51,10 @@ public AsymmetricSignerObject() { */ public abstract boolean doVerify(CertificateX509 cert, String plainText, String signature); + public abstract boolean doVerifyWithPublicKey(PublicKey key, String plainText, String signature, String hash); + public abstract boolean doVerifyFile(CertificateX509 cert, String path, String signature); + public abstract boolean doVerifyFileWithPublicKey(PublicKey key, String path, String signature, String hash); + } diff --git a/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java b/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java index 3a9f1b0..b9a12e2 100644 --- a/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java +++ b/GeneXusJWT/src/main/java/com/genexus/JWT/JWTCreator.java @@ -26,7 +26,6 @@ import com.genexus.commons.JWTObject; import com.genexus.commons.JWTOptions; import com.genexus.securityapicommons.config.EncodingUtil; -import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; import com.genexus.securityapicommons.utils.SecurityUtils; @@ -46,30 +45,84 @@ public JWTCreator() { public String doCreate(String algorithm, PrivateClaims privateClaims, JWTOptions options) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("algorithm", algorithm, this.error); + SecurityUtils.validateObjectInput("privateClaims", privateClaims, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if(this.hasError()) + { + return ""; + } + /******* INPUT VERIFICATION - END *******/ return create_Aux(algorithm, privateClaims, options, null, true); } public String doCreateFromJSON(String algorithm, String json, JWTOptions options) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("algorithm", algorithm, this.error); + SecurityUtils.validateStringInput("json", json, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if(this.hasError()) + { + return ""; + } + /******* INPUT VERIFICATION - END *******/ return create_Aux(algorithm, null, options, json, false); } public boolean doVerify(String token, String expectedAlgorithm, PrivateClaims privateClaims, JWTOptions options) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + SecurityUtils.validateStringInput("expectedAlgorithm", expectedAlgorithm, this.error); + SecurityUtils.validateObjectInput("privateClaims", privateClaims, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if(this.hasError()) + { + return false; + } + /******* INPUT VERIFICATION - END *******/ return doVerify(token, expectedAlgorithm, privateClaims, options, true, true); } public boolean doVerifyJustSignature(String token, String expectedAlgorithm, JWTOptions options) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + SecurityUtils.validateStringInput("expectedAlgorithm", expectedAlgorithm, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if(this.hasError()) + { + return false; + } + /******* INPUT VERIFICATION - END *******/ return doVerify(token, expectedAlgorithm, null, options, false, false); } public boolean doVerifySignature(String token, String expectedAlgorithm, JWTOptions options) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + SecurityUtils.validateStringInput("expectedAlgorithm", expectedAlgorithm, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if(this.hasError()) + { + return false; + } + /******* INPUT VERIFICATION - END *******/ return doVerify(token, expectedAlgorithm, null, options, false, true); } public String getPayload(String token) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + if(this.hasError()) + { + return ""; + } + /******* INPUT VERIFICATION - END *******/ this.error.cleanError(); String res = ""; try { @@ -84,6 +137,13 @@ public String getPayload(String token) { public String getHeader(String token) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + if(this.hasError()) + { + return ""; + } + /******* INPUT VERIFICATION - END *******/ String res = ""; try { res = getTokenPart(token, "header"); @@ -96,6 +156,13 @@ public String getHeader(String token) { public String getTokenID(String token) { this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("token", token, this.error); + if (this.hasError()) + { + return ""; + } + /******* INPUT VERIFICATION - END *******/ String res = ""; try { @@ -114,7 +181,7 @@ private String create_Aux(String algorithm, PrivateClaims privateClaims, JWTOpti boolean hasClaims) { if (options == null) { - this.error.setError("JW000", "Options parameter is null"); + this.error.setError("JW004", "Options parameter is null"); return ""; } JWTAlgorithm alg = JWTAlgorithm.getJWTAlgorithm(algorithm, this.error); @@ -129,7 +196,7 @@ private String create_Aux(String algorithm, PrivateClaims privateClaims, JWTOpti if (hasClaims) { if(privateClaims == null) { - this.error.setError("JW000", "PrivateClaims parameter is null"); + this.error.setError("JW005", "PrivateClaims parameter is null"); return ""; } tokenBuilder = doBuildPayload(tokenBuilder, privateClaims, options); @@ -172,7 +239,7 @@ private String create_Aux(String algorithm, PrivateClaims privateClaims, JWTOpti try { signedJwt = tokenBuilder.sign(algorithmType); } catch (Exception e) { - this.error.setError("JW003", e.getMessage()); + this.error.setError("JW006", e.getMessage()); return ""; } @@ -183,7 +250,7 @@ private boolean doVerify(String token, String expectedAlgorithm, PrivateClaims p boolean verifyClaims, boolean verifyRegClaims) { if (options == null) { - this.error.setError("JW004", "Options parameter is null"); + this.error.setError("JW007", "Options parameter is null"); return false; } DecodedJWT decodedJWT = null; @@ -191,7 +258,7 @@ private boolean doVerify(String token, String expectedAlgorithm, PrivateClaims p decodedJWT = JWT.decode(token); } catch (Exception e) { - this.error.setError("JW007", e.getMessage()); + this.error.setError("JW008", e.getMessage()); return false; } if (isRevoqued(decodedJWT, options)) { @@ -209,13 +276,18 @@ private boolean doVerify(String token, String expectedAlgorithm, PrivateClaims p } JWTAlgorithm expectedJWTAlgorithm = JWTAlgorithm.getJWTAlgorithm(expectedAlgorithm, this.error); if (alg.compareTo(expectedJWTAlgorithm) != 0 || this.hasError()) { - this.error.setError("JW008", "Expected algorithm does not match token algorithm"); + this.error.setError("JW009", "Expected algorithm does not match token algorithm"); return false; } Algorithm algorithmType = null; if (JWTAlgorithm.isPrivate(alg)) { - CertificateX509 cert = options.getCertificate(); + com.genexus.securityapicommons.commons.PublicKey cert = options.getPublicKey(); + if(cert == null) + { + this.error.setError("JW010", "The public key is null. Load a public key or certificate on JWTOptions object"); + return false; + } if (cert.hasError()) { this.error = cert.getError(); return false; @@ -242,7 +314,7 @@ private boolean doVerify(String token, String expectedAlgorithm, PrivateClaims p verifier.verify(decodedToken); } catch (Exception e) { - error.setError("JW009", e.getMessage()); + error.setError("JW011", e.getMessage()); return false; } @@ -263,7 +335,7 @@ private String getTokenPart(String token, String part) throws Exception { case "id": return decodedToken.getId(); default: - error.setError("JW010", "Unknown token segment"); + error.setError("JW012", "Unknown token segment"); return ""; } byte[] base64Bytes = Base64.decodeBase64(base64Part); @@ -304,7 +376,7 @@ private Verification buildVerification(Verification verification, JWTOptions opt return null; } } else { - error.setError("JW011", String.format("%s wrong registered claim key", registeredC.get(z).getKey())); + error.setError("JW013", String.format("%s wrong registered claim key", registeredC.get(z).getKey())); return null; } } @@ -334,12 +406,12 @@ private Builder doBuildPayload(Builder tokenBuilder, PrivateClaims privateClaims } else if (obj instanceof Boolean) { tokenBuilder.withClaim(privateC.get(i).getKey(), (boolean) privateC.get(i).getValue()); } else { - this.error.setError("JW016", "Unrecognized data type"); + this.error.setError("JW014", "Unrecognized data type"); } // tokenBuilder.withClaim(privateC.get(i).getKey(), privateC.get(i).getValue()); } } catch (Exception e) { - this.error.setError("JW012", e.getMessage()); + this.error.setError("JW015", e.getMessage()); return null; } } @@ -351,7 +423,7 @@ private Builder doBuildPayload(Builder tokenBuilder, PrivateClaims privateClaims try { tokenBuilder.withClaim(publicC.get(j).getKey(), (String) publicC.get(j).getValue()); } catch (Exception e) { - this.error.setError("JW013", e.getMessage()); + this.error.setError("JW016", e.getMessage()); return null; } } @@ -368,7 +440,7 @@ private Builder doBuildPayload(Builder tokenBuilder, PrivateClaims privateClaims return null; } } else { - error.setError("JW011", String.format("%s wrong registered claim key", registeredC.get(z).getKey())); + error.setError("JW017", String.format("%s wrong registered claim key", registeredC.get(z).getKey())); return null; } } @@ -394,7 +466,7 @@ private boolean verifyPrivateClaims(DecodedJWT decodedJWT, PrivateClaims private map = (HashMap) mapper.readValue(plainTextPart, new TypeReference>() { }); } catch (Exception e) { - this.error.setError("JW014", e.getMessage()); + this.error.setError("JW018", e.getMessage()); return false; } this.counter = 0; diff --git a/GeneXusJWT/src/main/java/com/genexus/JWT/utils/JWTAlgorithm.java b/GeneXusJWT/src/main/java/com/genexus/JWT/utils/JWTAlgorithm.java index ef40ef2..9938639 100644 --- a/GeneXusJWT/src/main/java/com/genexus/JWT/utils/JWTAlgorithm.java +++ b/GeneXusJWT/src/main/java/com/genexus/JWT/utils/JWTAlgorithm.java @@ -1,8 +1,15 @@ package com.genexus.JWT.utils; + + +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + import com.auth0.jwt.algorithms.Algorithm; import com.genexus.securityapicommons.commons.Error; -import com.genexus.securityapicommons.keys.CertificateX509; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.keys.PrivateKeyManager; public enum JWTAlgorithm { @@ -83,7 +90,7 @@ public static Algorithm getSymmetricAlgorithm(JWTAlgorithm algorithm, byte[] sec } - public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKeyManager key, CertificateX509 cert, + public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKeyManager key, PublicKey cert, Error error) { if (!isPrivate(algorithm)) { error.setError("JWA07", "It is not an asymmetric algorithm name"); @@ -94,10 +101,10 @@ public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKe try { if (cert == null) { if (key != null) - return Algorithm.RSA256(null, key.getRSAPrivateKeyJWT()); + return Algorithm.RSA256(null, (RSAPrivateKey)key.getPrivateKey()); } else { - return (key != null) ? Algorithm.RSA256(cert.getRSAPublicKey(), key.getRSAPrivateKeyJWT()) - : Algorithm.RSA256(cert.getRSAPublicKey(), null); + return (key != null) ? Algorithm.RSA256((RSAPublicKey)cert.getPublicKey(), (RSAPrivateKey)key.getPrivateKey()) + : Algorithm.RSA256((RSAPublicKey)cert.getPublicKey(), null); } } catch (Exception e) { error.setError("JWA08", e.getMessage()); @@ -107,10 +114,10 @@ public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKe try { if (cert == null) { if (key != null) - return Algorithm.RSA512(null, key.getRSAPrivateKeyJWT()); + return Algorithm.RSA512(null, (RSAPrivateKey)key.getPrivateKey()); } else { - return (key != null) ? Algorithm.RSA512(cert.getRSAPublicKey(), key.getRSAPrivateKeyJWT()) - : Algorithm.RSA512(cert.getRSAPublicKey(), null); + return (key != null) ? Algorithm.RSA512((RSAPublicKey)cert.getPublicKey(), (RSAPrivateKey)key.getPrivateKey()) + : Algorithm.RSA512((RSAPublicKey)cert.getPublicKey(), null); } } catch (Exception e) { error.setError("JWA09", e.getMessage()); @@ -120,10 +127,10 @@ public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKe try { if (cert == null) { if (key != null) - return Algorithm.ECDSA256(null, key.getECPrivateKeyJWT()); + return Algorithm.ECDSA256(null, (ECPrivateKey)key.getPrivateKey()); } else { - return (key != null) ? Algorithm.ECDSA256(cert.getECPublicKeyJWT(), key.getECPrivateKeyJWT()) - : Algorithm.ECDSA256(cert.getECPublicKeyJWT(), null); + return (key != null) ? Algorithm.ECDSA256((ECPublicKey)cert.getPublicKey(), (ECPrivateKey)key.getPrivateKey()) + : Algorithm.ECDSA256((ECPublicKey)cert.getPublicKey(), null); } } catch (Exception e) { error.setError("JWA10", e.getMessage()); @@ -133,10 +140,10 @@ public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKe try { if (cert == null) { if (key != null) - return Algorithm.ECDSA384(null, key.getECPrivateKeyJWT()); + return Algorithm.ECDSA384(null, (ECPrivateKey)key.getPrivateKey()); } else { - return (key != null) ? Algorithm.ECDSA384(cert.getECPublicKeyJWT(), key.getECPrivateKeyJWT()) - : Algorithm.ECDSA384(cert.getECPublicKeyJWT(), null); + return (key != null) ? Algorithm.ECDSA384((ECPublicKey)cert.getPublicKey(), (ECPrivateKey)key.getPrivateKey()) + : Algorithm.ECDSA384((ECPublicKey)cert.getPublicKey(), null); } } catch (Exception e) { error.setError("JWA11", e.getMessage()); @@ -146,10 +153,10 @@ public static Algorithm getAsymmetricAlgorithm(JWTAlgorithm algorithm, PrivateKe try { if (cert == null) { if (key != null) - return Algorithm.ECDSA512(null, key.getECPrivateKeyJWT()); + return Algorithm.ECDSA512(null, (ECPrivateKey)key.getPrivateKey()); } else { - return (key != null) ? Algorithm.ECDSA512(cert.getECPublicKeyJWT(), key.getECPrivateKeyJWT()) - : Algorithm.ECDSA512(cert.getECPublicKeyJWT(), null); + return (key != null) ? Algorithm.ECDSA512((ECPublicKey)cert.getPublicKey(), (ECPrivateKey)key.getPrivateKey()) + : Algorithm.ECDSA512((ECPublicKey)cert.getPublicKey(), null); } } catch (Exception e) { error.setError("JWA12", e.getMessage()); diff --git a/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java b/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java index 7019d9e..1176c19 100644 --- a/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java +++ b/GeneXusJWT/src/main/java/com/genexus/commons/JWTOptions.java @@ -6,6 +6,8 @@ import com.genexus.JWT.claims.PublicClaims; import com.genexus.JWT.claims.RegisteredClaims; import com.genexus.JWT.utils.RevocationList; +import com.genexus.securityapicommons.commons.Key; +import com.genexus.securityapicommons.commons.PublicKey; import com.genexus.securityapicommons.commons.SecurityAPIObject; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; @@ -19,6 +21,7 @@ public class JWTOptions extends SecurityAPIObject { private RevocationList revocationList; private CertificateX509 certificate; private PrivateKeyManager privateKey; + private PublicKey publicKey; private HeaderParameters parameters; public JWTOptions() { @@ -34,6 +37,10 @@ public void setPrivateKey(PrivateKeyManager key) { this.privateKey = key; } + public void setPublicKey(PublicKey key) { + this.publicKey = key; + } + public void setCertificate(CertificateX509 cert) { this.certificate = cert; } @@ -81,9 +88,13 @@ public void addHeaderParameter(String name, String value) this.parameters.setParameter(name, value); } - /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + public PublicKey getPublicKey() + { + return (this.certificate == null) ? this.publicKey: this.certificate; + } + public boolean hasPublicClaims() { return !publicClaims.isEmpty(); } @@ -117,9 +128,9 @@ public RevocationList getRevocationList() { return this.revocationList; } - public CertificateX509 getCertificate() { + /*public CertificateX509 getCertificate() { return this.certificate; - } + }*/ public PrivateKeyManager getPrivateKey() { return this.privateKey; diff --git a/GeneXusXmlSignature/src/main/java/com/genexus/dsig/XmlDSigSigner.java b/GeneXusXmlSignature/src/main/java/com/genexus/dsig/XmlDSigSigner.java index 05b9959..b1fdcda 100644 --- a/GeneXusXmlSignature/src/main/java/com/genexus/dsig/XmlDSigSigner.java +++ b/GeneXusXmlSignature/src/main/java/com/genexus/dsig/XmlDSigSigner.java @@ -20,6 +20,7 @@ import com.genexus.commons.DSigOptions; import com.genexus.config.Config; import com.genexus.securityapicommons.commons.Certificate; +import com.genexus.securityapicommons.commons.Key; import com.genexus.securityapicommons.commons.SecurityAPIObject; import com.genexus.securityapicommons.keys.CertificateX509; import com.genexus.securityapicommons.keys.PrivateKeyManager; @@ -54,54 +55,251 @@ public XmlDSigSigner() { /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ - public boolean doSignFile(String xmlFilePath, com.genexus.securityapicommons.commons.PrivateKey key, + public boolean doSignFile(String xmlFilePath, com.genexus.securityapicommons.commons.PrivateKey privateKey, Certificate certificate, String outputPath, DSigOptions options) { - return Boolean.valueOf(axuiliarSign(xmlFilePath, key, certificate, outputPath, options, true, "")); + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateStringInput("outputPath", outputPath, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + return Boolean.valueOf(axuiliarSign(xmlFilePath, privateKey, certificate, outputPath, options, true, "", null)); + } + + public boolean doSignFileWithPublicKey(String xmlFilePath, com.genexus.securityapicommons.commons.PrivateKey privateKey, com.genexus.securityapicommons.commons.PublicKey publicKey, String outputPath, DSigOptions options, String hash) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateStringInput("outputPath", outputPath, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + SecurityUtils.validateStringInput("hash", hash, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + return Boolean.valueOf(axuiliarSign(xmlFilePath, privateKey, publicKey, outputPath, options, true, "", hash)); } - public String doSign(String xmlInput, com.genexus.securityapicommons.commons.PrivateKey key, + public String doSign(String xmlInput, com.genexus.securityapicommons.commons.PrivateKey privateKey, Certificate certificate, DSigOptions options) { - return axuiliarSign(xmlInput, key, certificate, "", options, false, ""); + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlInput", xmlInput, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + + return axuiliarSign(xmlInput, privateKey, certificate, "", options, false, "", null); + } + + public String doSignWithPublicKey(String xmlInput, com.genexus.securityapicommons.commons.PrivateKey privateKey , com.genexus.securityapicommons.commons.PublicKey publicKey,DSigOptions options, String hash) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlInput", xmlInput, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + SecurityUtils.validateStringInput("hash", hash, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + + return axuiliarSign(xmlInput, privateKey, publicKey, "", options, false, "", hash); } public boolean doSignFileElement(String xmlFilePath, String xPath, - com.genexus.securityapicommons.commons.PrivateKey key, Certificate certificate, String outputPath, + com.genexus.securityapicommons.commons.PrivateKey privateKey, Certificate certificate, String outputPath, DSigOptions options) { - return Boolean.valueOf(axuiliarSign(xmlFilePath, key, certificate, outputPath, options, true, xPath)); + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateStringInput("outputPath", outputPath, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + return Boolean.valueOf(axuiliarSign(xmlFilePath, privateKey, certificate, outputPath, options, true, xPath, null)); + } + + public boolean doSignFileElementWithPublicKey(String xmlFilePath, String xPath, + com.genexus.securityapicommons.commons.PrivateKey privateKey, com.genexus.securityapicommons.commons.PublicKey publicKey, String outputPath, + DSigOptions options, String hash) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateStringInput("xPath", xPath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateStringInput("outputPath", outputPath, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + SecurityUtils.validateStringInput("hash", hash, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + return Boolean.valueOf(axuiliarSign(xmlFilePath, privateKey, publicKey, outputPath, options, true, xPath, hash)); } - public String doSignElement(String xmlInput, String xPath, com.genexus.securityapicommons.commons.PrivateKey key, + public String doSignElement(String xmlInput, String xPath, com.genexus.securityapicommons.commons.PrivateKey privateKey, Certificate certificate, DSigOptions options) { - return axuiliarSign(xmlInput, key, certificate, "", options, false, xPath); + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlInput", xmlInput, this.error); + SecurityUtils.validateStringInput("xPath", xPath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + + return axuiliarSign(xmlInput, privateKey, certificate, "", options, false, xPath, null); + } + + public String doSignElementWithPublicKey(String xmlInput, String xPath, com.genexus.securityapicommons.commons.PrivateKey privateKey, com.genexus.securityapicommons.commons.PublicKey publicKey + ,DSigOptions options, String hash) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlInput", xmlInput, this.error); + SecurityUtils.validateStringInput("xPath", xPath, this.error); + SecurityUtils.validateObjectInput("privateKey", privateKey, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + SecurityUtils.validateStringInput("hash", hash, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + + return axuiliarSign(xmlInput, privateKey, publicKey, "", options, false, xPath, hash); } public boolean doVerify(String xmlSigned, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlSigned", xmlSigned, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + return auxiliarVerify(xmlSigned, options, false, false, null); } public boolean doVerifyFile(String xmlFilePath, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + return auxiliarVerify(xmlFilePath, options, true, false, null); } public boolean doVerifyWithCert(String xmlSigned, Certificate certificate, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlSigned", xmlSigned, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + return auxiliarVerify(xmlSigned, options, false, true, certificate); + } public boolean doVerifyFileWithCert(String xmlFilePath, Certificate certificate, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("certificate", certificate, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + return auxiliarVerify(xmlFilePath, options, true, true, certificate); } + + public boolean doVerifyWithPublicKey(String xmlSigned, com.genexus.securityapicommons.commons.PublicKey publicKey, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlSigned", xmlSigned, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + + return auxiliarVerify(xmlSigned, options, false, true, publicKey); + } + + public boolean doVerifyFileWithPublicKey(String xmlFilePath, com.genexus.securityapicommons.commons.PublicKey publicKey, DSigOptions options) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("xmlFilePath", xmlFilePath, this.error); + SecurityUtils.validateObjectInput("publicKey", publicKey, this.error); + SecurityUtils.validateObjectInput("options", options, this.error); + if (this.hasError()) { + return false; + } + /******* INPUT VERIFICATION - END *******/ + + return auxiliarVerify(xmlFilePath, options, true, true, publicKey); + } /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ private String axuiliarSign(String xmlInput, com.genexus.securityapicommons.commons.PrivateKey key, - Certificate certificate, String outputPath, DSigOptions options, boolean isFile, String xPath) { + Key publicKey, String outputPath, DSigOptions options, boolean isFile, String xPath, String hash) { if (TransformsWrapper.getTransformsWrapper(options.getDSigSignatureType(), this.error) != TransformsWrapper.ENVELOPED) { error.setError("XD001", "Not implemented DSigType"); } - CertificateX509 cert = (CertificateX509) certificate; - if (!cert.Inicialized()) { - this.error.setError("XD002", "Certificate not loaded"); + + com.genexus.securityapicommons.commons.PublicKey cert = null; + cert = (hash != null) ? (com.genexus.securityapicommons.commons.PublicKey) publicKey:(CertificateX509) publicKey; + if (cert.hasError()) { + this.error = cert.getError(); + return ""; } Document xmlDoc = loadDocument(isFile, xmlInput, options); @@ -109,16 +307,21 @@ private String axuiliarSign(String xmlInput, com.genexus.securityapicommons.comm return ""; } String result = Sign(xmlDoc, (PrivateKeyManager) key, cert, options.getDSigSignatureType(), - options.getCanonicalization(), options.getKeyInfoType(), xPath, options.getIdentifierAttribute()); + options.getCanonicalization(), options.getKeyInfoType(), xPath, options.getIdentifierAttribute(), hash); if (isFile) { - String prefix = ""; - result = Boolean.toString(SignatureUtils.writeToFile(result, outputPath, prefix, this.error)); + if ((result == null) || SecurityUtils.compareStrings(result, "")) { + result = "false"; + } else { + String prefix = ""; + result = Boolean.toString(SignatureUtils.writeToFile(result, outputPath, prefix, this.error)); + } } return result; } - private String Sign(Document xmlInput, PrivateKeyManager key, CertificateX509 certificate, String dSigType, - String canonicalizationType, String keyInfoType, String xpath, String id) { + private String Sign(Document xmlInput, PrivateKeyManager key, com.genexus.securityapicommons.commons.PublicKey certificate, String dSigType, + String canonicalizationType, String keyInfoType, String xpath, String id, String hash) { + SignatureElementType signatureElementType; if (!SecurityUtils.compareStrings(xpath, "")) { if (xpath.charAt(0) == '#') { @@ -133,10 +336,7 @@ private String Sign(Document xmlInput, PrivateKeyManager key, CertificateX509 ce } else { signatureElementType = SignatureElementType.document; } - boolean inicialized = inicializeInstanceVariables(key, certificate); - if (!inicialized) { - return ""; - } + inicializeInstanceVariables(key, certificate, hash); Element rootElement = SignatureUtils.getRootElement(xmlInput); CanonicalizerWrapper canonicalizerWrapper = CanonicalizerWrapper.getCanonicalizerWrapper(canonicalizationType, @@ -219,8 +419,13 @@ private String Sign(Document xmlInput, PrivateKeyManager key, CertificateX509 ce case X509Certificate: + if(hash != null) + { + this.error.setError("XD002", "The file included is a Public Key, cannot include a certificate on the signature"); + return ""; + } try { - X509Certificate x509Certificate = certificate.Cert(); + X509Certificate x509Certificate = ((CertificateX509)certificate).Cert(); X509Data x509data = new X509Data(sig.getDocument()); x509data.addIssuerSerial(x509Certificate.getIssuerDN().getName(), x509Certificate.getSerialNumber()); x509data.addSubjectName(x509Certificate); @@ -254,17 +459,21 @@ private String Sign(Document xmlInput, PrivateKeyManager key, CertificateX509 ce return new String(bos.toByteArray()); } - private boolean inicializeInstanceVariables(PrivateKeyManager key, CertificateX509 certificate) { + private void inicializeInstanceVariables(PrivateKeyManager key, com.genexus.securityapicommons.commons.PublicKey certificate, String hash) { - this.privateKey = key.getPrivateKeyXML(); - this.publicKey = certificate.getPublicKeyXML(); - this.digest = certificate.getPublicKeyHash(); - this.asymAlgorithm = certificate.getPublicKeyAlgorithm(); - return true; + this.privateKey = key.getPrivateKey(); + this.publicKey = certificate.getPublicKey(); + this.asymAlgorithm = certificate.getAlgorithm(); + if (hash == null) { + this.digest = ((CertificateX509)certificate).getPublicKeyHash(); + }else + { + this.digest = hash; + } } private boolean auxiliarVerify(String input, DSigOptions options, boolean isFile, boolean withCert, - Certificate certificate) { + Key key) { if (TransformsWrapper.getTransformsWrapper(options.getDSigSignatureType(), this.error) != TransformsWrapper.ENVELOPED) { error.setError("XD001", "Not implemented DSigType"); @@ -284,10 +493,10 @@ private boolean auxiliarVerify(String input, DSigOptions options, boolean isFile return false; } } - return verify(doc, baseURI, options.getIdentifierAttribute(), withCert, (CertificateX509) certificate); + return verify(doc, baseURI, options.getIdentifierAttribute(), withCert, key); } - private boolean verify(Document doc, String baseURI, String id, boolean withCert, CertificateX509 certificate) { + private boolean verify(Document doc, String baseURI, String id, boolean withCert, Key key) { Element sigElement = (Element) doc.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE) .item(0); if (id != null && !SecurityUtils.compareStrings(id, "")) { @@ -312,7 +521,7 @@ private boolean verify(Document doc, String baseURI, String id, boolean withCert XMLSignature signature = new XMLSignature(sigElement, baseURI); if (withCert) { - PublicKey pk = certificate.getPublicKeyXML(); + PublicKey pk = ((com.genexus.securityapicommons.commons.PublicKey)key).getPublicKey(); result = signature.checkSignatureValue(pk); } else { result = signature.checkSignatureValue(signature.getKeyInfo().getPublicKey()); diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Certificate.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Certificate.java index 2535c95..8d0ab1b 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Certificate.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Certificate.java @@ -1,6 +1,6 @@ package com.genexus.securityapicommons.commons; -public abstract class Certificate extends Key { +public abstract class Certificate extends PublicKey { public Certificate() { super(); diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Error.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Error.java index f5860d4..2ddf44c 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Error.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Error.java @@ -33,6 +33,13 @@ public Error() { this.code = ""; this.description = ""; } + + public Error(String code, String description) + { + this.code = code; + this.description = description; + this.exists = true; + } /** * Set error values diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Key.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Key.java index 35d1d88..9a6445f 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Key.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/Key.java @@ -1,10 +1,24 @@ package com.genexus.securityapicommons.commons; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; + public class Key extends SecurityAPIObject { public Key() { super(); } + + protected String algorithm; + + public String getAlgorithm() + { + return this.algorithm; + } - + public boolean load(String path) {return false; } + public boolean loadPKCS12(String path, String alias, String password) { return false; } + public boolean fromBase64(String base64) { return false; } + public String toBase64() { return ""; } + protected void setAlgorithm() {} + public AsymmetricKeyParameter getAsymmetricKeyParameter() {return null; } } diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PrivateKey.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PrivateKey.java index 8bdb776..5482ebf 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PrivateKey.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PrivateKey.java @@ -5,9 +5,6 @@ public abstract class PrivateKey extends Key{ public PrivateKey() { super(); } - public abstract boolean load(String path); - public abstract boolean loadPKCS12(String path, String alias, String password); + public abstract boolean loadEncrypted(String privateKeyPath, String encryptionPassword); - public abstract boolean fromBase64(String base64); - public abstract String toBase64(); } diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PublicKey.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PublicKey.java new file mode 100644 index 0000000..ef63b17 --- /dev/null +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/commons/PublicKey.java @@ -0,0 +1,188 @@ +package com.genexus.securityapicommons.commons; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.spec.X509EncodedKeySpec; + +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.util.encoders.Base64; + +import com.genexus.securityapicommons.utils.SecurityUtils; + +public class PublicKey extends Key { + + protected SubjectPublicKeyInfo subjectPublicKeyInfo; + + public PublicKey() { + super(); + } + + /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + @Override + public boolean load(String path) { + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", path, this.error); + if (!(SecurityUtils.extensionIs(path, ".pem") || SecurityUtils.extensionIs(path, "key"))) { + this.error.setError("PU001", "Public key should be loaded from a .pem or .key file"); + return false; + } + /******* INPUT VERIFICATION - END *******/ + boolean loaded = false; + try { + loaded = loadPublicKeyFromFile(path); + } catch (Exception e) { + this.error.setError("PU002", e.getMessage()); + return false; + } + return loaded; + } + + @Override + public boolean fromBase64(String base64Data) { + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("base64Data", base64Data, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + boolean flag; + try { + byte[] dataBuffer = Base64.decode(base64Data); + this.subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(dataBuffer)); + flag = true; + } catch (Exception e) { + this.error.setError("PU003", e.getMessage()); + flag = false; + } + setAlgorithm(); + + return flag; + } + + @Override + public String toBase64() { + if (this.subjectPublicKeyInfo == null) { + this.error.setError("PU004", "Not loaded key"); + return ""; + } + String base64Encoded = ""; + + try { + base64Encoded = new String(Base64.encode(this.subjectPublicKeyInfo.getEncoded())); + + } catch (Exception e) { + this.error.setError("PU005", e.getMessage()); + } + + return base64Encoded; + } + + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + + @Override + protected void setAlgorithm() { + if (this.subjectPublicKeyInfo == null) { + return; + } + String alg = this.subjectPublicKeyInfo.getAlgorithm().getAlgorithm().getId(); + switch (alg) { + case "1.2.840.113549.1.1.1": + this.algorithm = "RSA"; + break; + case "1.2.840.10045.2.1": + this.algorithm = "ECDSA"; + break; + } + + } + + @Override + public AsymmetricKeyParameter getAsymmetricKeyParameter() { + AsymmetricKeyParameter akp = null; + try { + akp = PublicKeyFactory.createKey(this.subjectPublicKeyInfo); + } catch (Exception e) { + this.error.setError("PU006", e.getMessage()); + return null; + } + return akp; + } + + /** + * @return PublicKey type for the key type + */ + public java.security.PublicKey getPublicKey() { + java.security.PublicKey pk = null; + try { + KeyFactory kf = SecurityUtils.getKeyFactory(this.algorithm); + X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(this.subjectPublicKeyInfo.getEncoded()); + pk = kf.generatePublic(encodedKeySpec); + } catch (Exception e) { + this.error.setError("PU007", e.getMessage()); + return null; + } + return pk; + } + + private boolean loadPublicKeyFromFile(String path) throws IOException { + boolean flag = false; + try (FileReader privateKeyReader = new FileReader(new File(path))) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj; + obj = parser.readObject(); + if (obj instanceof PrivateKeyInfo) { + this.error.setError("PU008", "The file contains a private key"); + flag = false; + } + if (obj instanceof SubjectPublicKeyInfo) { + this.subjectPublicKeyInfo = (SubjectPublicKeyInfo) obj; + setAlgorithm(); + flag = true; + } + if (obj instanceof PEMKeyPair) { + PEMKeyPair keypair = (PEMKeyPair) obj; + this.subjectPublicKeyInfo = keypair.getPublicKeyInfo(); + setAlgorithm(); + flag = true; + } + if (obj instanceof ECPublicKeyParameters) { + ECPublicKeyParameters ecParms = (ECPublicKeyParameters) obj; + this.subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(ecParms); + setAlgorithm(); + flag = true; + } + if (obj instanceof RSAKeyParameters) { + RSAKeyParameters rsaParms = (RSAKeyParameters) obj; + this.subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(rsaParms); + setAlgorithm(); + flag = true; + } + if (obj instanceof X509CertificateHolder) { + this.error.setError("PU009", "This file contains a certificate, use the Certificate object instead"); + flag = false; + } + } + } + if (!flag && !this.hasError()) { + this.error.setError("PU010", "Error loading public key from file"); + } + return flag; + } + +} diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/CertificateX509.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/CertificateX509.java index 1d654e1..d40c63c 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/CertificateX509.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/CertificateX509.java @@ -5,7 +5,6 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; -import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -13,18 +12,11 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; import java.util.Date; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.RSAKeyParameters; -import org.bouncycastle.crypto.util.PublicKeyFactory; import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; @@ -34,7 +26,7 @@ public class CertificateX509 extends com.genexus.securityapicommons.commons.Certificate { - private String publicKeyAlgorithm; + private String algorithmWithHash; private boolean hasPublicKey; private X509Certificate cert; public String issuer; @@ -44,7 +36,6 @@ public class CertificateX509 extends com.genexus.securityapicommons.commons.Cert public Date notAfter; public Date notBefore; public int version; - private SubjectPublicKeyInfo subjectPublicKeyInfo; private boolean inicialized; /** @@ -67,11 +58,35 @@ public X509Certificate Cert() { /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ @Override public boolean load(String path) { - return loadPKCS12(path, "", ""); + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", path, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + boolean result = loadPKCS12(path, "", ""); + if(result) + { + this.inicialized = true; + } + setAlgorithm(); + return result; } @Override public boolean loadPKCS12(String path, String alias, String password) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", path, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + boolean result = false; try { result = loadPublicKeyFromFile(path, alias, password); @@ -80,14 +95,23 @@ public boolean loadPKCS12(String path, String alias, String password) { return false; } if (result) { - - inicializeParameters(); + inicializeParameters(); + setAlgorithm(); } return result; } @Override public boolean fromBase64(String base64Data) { + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("base64Data", base64Data, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + boolean flag; try { byte[] dataBuffer = Base64.decode(base64Data); @@ -97,13 +121,11 @@ public boolean fromBase64(String base64Data) { inicializeParameters(); flag = true; } catch (Exception e) { - this.error.setError("CE002", "Error loading certificate from base64"); + this.error.setError("CE002", e.getMessage()); flag = false; } - if (flag) { - - inicializeParameters(); - } + setAlgorithm(); + return flag; } @@ -119,7 +141,7 @@ public String toBase64() { base64Encoded = new String(Base64.encode(this.cert.getEncoded())); } catch (Exception e) { - this.error.setError("CE004", "Error encoding certificate to base64"); + this.error.setError("CE004", e.getMessage()); } return base64Encoded; @@ -131,116 +153,13 @@ public String toBase64() { * @return String certificate-s hash algorithm for sign verification */ public String getPublicKeyHash() { - String[] aux = this.publicKeyAlgorithm.toUpperCase().split("WITH"); + String[] aux = this.algorithmWithHash.toUpperCase().split("WITH"); if (SecurityUtils.compareStrings(aux[0], "1.2.840.10045.2.1")) { return "ECDSA"; } return aux[0]; } - public AsymmetricKeyParameter getPublicKeyParameterForEncryption() { - - if (SecurityUtils.compareStrings(this.getPublicKeyAlgorithm(), "RSA")) { - return getRSAKeyParameter(); - } else { - - this.error.setError("AE009", "Unrecognized encryption algorithm"); - return null; - } - } - - /** - * @return AsymmetricKeyParameter with loaded public key for RSA or ECDSA - * signature verification - */ - public AsymmetricKeyParameter getPublicKeyParameterForSigning() { - - switch (this.getPublicKeyAlgorithm()) { - case "RSA": - return getRSAKeyParameter(); - case "ECDSA": - AsymmetricKeyParameter parmsECDSA; - try { - parmsECDSA = PublicKeyFactory.createKey(this.subjectPublicKeyInfo); - } catch (IOException e) { - this.error.setError("AE010", "Not ECDSA key"); - e.printStackTrace(); - return null; - } - return parmsECDSA; - default: - this.error.setError("AE011", "Unrecognized signing algorithm"); - return null; - } - } - - private AsymmetricKeyParameter getRSAKeyParameter() { - - RSAKeyParameters parms; - try { - parms = (RSAKeyParameters) PublicKeyFactory.createKey(this.subjectPublicKeyInfo); - } catch (IOException e) { - this.error.setError("AE014", "Not RSA key"); - e.printStackTrace(); - return null; - } - return parms; - } - - /** - * @return PublicKey type for the key type - */ - public PublicKey getPublicKeyXML() { - KeyFactory kf = null; - X509EncodedKeySpec encodedKeySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPublicKeyAlgorithm()); - encodedKeySpec = new X509EncodedKeySpec(this.subjectPublicKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("CE011", "Error reading algorithm"); - } - PublicKey pk = null; - if ((kf != null) && (encodedKeySpec != null)) { - try { - - pk = kf.generatePublic(encodedKeySpec); - } catch (InvalidKeySpecException e) { - // e.printStackTrace(); - this.error.setError("CE010", "Error casting public key data for XML signing"); - } - } - return pk; - - } - - /** - * @return RSAPublicKey type for the key type - */ - public RSAPublicKey getRSAPublicKeyJWT() { - KeyFactory kf = null; - X509EncodedKeySpec encodedKeySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPublicKeyAlgorithm()); - encodedKeySpec = new X509EncodedKeySpec(this.subjectPublicKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("CE011", "Error reading algorithm"); - } - RSAPublicKey pk = null; - if ((kf != null) && (encodedKeySpec != null)) { - try { - - pk = (RSAPublicKey) kf.generatePublic(encodedKeySpec); - } catch (InvalidKeySpecException e) { - // e.printStackTrace(); - this.error.setError("CE010", "Error casting public key data for XML signing"); - } - } - return pk; - - } - /** * stores SubjectPublicKeyInfo Data Type of public key from certificate, * algorithm and digest @@ -257,7 +176,7 @@ public RSAPublicKey getRSAPublicKeyJWT() { private boolean loadPublicKeyFromFile(String path, String alias, String password) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException { boolean result = false; - if (SecurityUtils.extensionIs(path, ".pem")) { + if (SecurityUtils.extensionIs(path, ".pem") || SecurityUtils.extensionIs(path, ".key")) { result = loadPublicKeyFromPEMFile(path); return result; } @@ -270,7 +189,7 @@ private boolean loadPublicKeyFromFile(String path, String alias, String password result = loadPublicKeyFromPKCS12File(path, alias, password); return result; } - this.error.setError("CE005", "Error loading public key"); + this.error.setError("CE005", "Error loading certificate"); this.hasPublicKey = false; return false; @@ -295,7 +214,7 @@ private boolean loadPublicKeyFromPKCS12File(String path, String alias, String pa throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { if (alias == null || password == null) { - this.error.setError("CE012", "Alias and password are required for PKCS12 certificates"); + this.error.setError("CE006", "Alias and password are required for PKCS12 certificates"); return false; } InputStream in; @@ -306,7 +225,7 @@ private boolean loadPublicKeyFromPKCS12File(String path, String alias, String pa ks.load(in, password.toCharArray()); this.cert = (X509Certificate) ks.getCertificate(alias); } catch (Exception e) { - this.error.setError("CE013", path + "not found."); + this.error.setError("CE007", "Path not found."); return false; } return true; @@ -324,32 +243,27 @@ private boolean loadPublicKeyFromPKCS12File(String path, String alias, String pa */ private boolean loadPublicKeyFromPEMFile(String path) throws IOException, CertificateException { boolean flag = false; - FileReader privateKeyReader; - privateKeyReader = new FileReader(new File(path)); - PEMParser parser = new PEMParser(privateKeyReader); - Object obj; - obj = parser.readObject(); - if (obj instanceof PrivateKeyInfo) { - this.error.setError("CE007", "The file contains a private key"); - flag = false; - } - if ((obj instanceof PEMKeyPair) || (obj instanceof SubjectPublicKeyInfo)) { - this.error.setError("CE008", "Invalid X509 Certificate format"); - flag = false; - } - if (obj instanceof X509CertificateHolder) { - X509CertificateHolder x509 = (X509CertificateHolder) obj; - CertificateFactory certFactory = new CertificateFactory(); - InputStream in; - in = new ByteArrayInputStream(x509.getEncoded()); - this.cert = (X509Certificate) certFactory.engineGenerateCertificate(in); - flag = true; - } - privateKeyReader.close(); - parser.close(); - if (!flag) { - this.error.setError("CE016", "Error loading public key from pem file"); + try (FileReader privateKeyReader = new FileReader(new File(path))) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj; + obj = parser.readObject(); + if (obj instanceof PrivateKeyInfo) { + this.error.setError("CE008", "The file contains a private key"); + } + if ((obj instanceof PEMKeyPair) || (obj instanceof SubjectPublicKeyInfo)){ + this.error.setError("CE009", "It is a public key not a certificate, use PublicKey Object instead"); + flag = false; + } + if (obj instanceof X509CertificateHolder) { + X509CertificateHolder x509 = (X509CertificateHolder) obj; + CertificateFactory certFactory = new CertificateFactory(); + InputStream in; + in = new ByteArrayInputStream(x509.getEncoded()); + this.cert = (X509Certificate) certFactory.engineGenerateCertificate(in); + flag = true; + } + } } return flag; } @@ -380,7 +294,7 @@ private void inicializeParameters() { this.thumbprint = ""; this.notAfter = this.cert.getNotAfter(); this.notBefore = this.cert.getNotBefore(); - this.publicKeyAlgorithm = this.cert.getSigAlgName(); + this.algorithmWithHash = this.cert.getSigAlgName(); extractPublicInfo(); this.inicialized = true; } @@ -395,72 +309,4 @@ private void extractPublicInfo() { PublicKey publicKey = cert1.getPublicKey(); this.subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); } - - /** - * @return RSAPublicKey type for the key type - */ - public RSAPublicKey getRSAPublicKey() { - KeyFactory kf = null; - X509EncodedKeySpec encodedKeySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPublicKeyAlgorithm()); - encodedKeySpec = new X509EncodedKeySpec(this.subjectPublicKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("CE011", "Error reading algorithm"); - } - RSAPublicKey pk = null; - if ((kf != null) && (encodedKeySpec != null)) { - try { - - pk = (RSAPublicKey) kf.generatePublic(encodedKeySpec); - } catch (InvalidKeySpecException e) { - // e.printStackTrace(); - this.error.setError("CE010", "Error casting public key data for XML signing"); - } - } - return pk; - - } - - /** - * @return String certificate-s asymmetric algorithm for sign verification - */ - public String getPublicKeyAlgorithm() { - if (SecurityUtils.compareStrings(this.publicKeyAlgorithm, "1.2.840.10045.2.1") || SecurityUtils.compareStrings(this.publicKeyAlgorithm, "ECDSA")) { - return "ECDSA"; - } - String[] aux = this.publicKeyAlgorithm.toUpperCase().split("WITH"); - return aux[1]; - } - - /** - * @return ECPublicKey type for the key type - */ - public ECPublicKey getECPublicKeyJWT() { - KeyFactory kf = null; - X509EncodedKeySpec encodedKeySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPublicKeyAlgorithm()); - encodedKeySpec = new X509EncodedKeySpec(this.subjectPublicKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("CE017", "Error reading algorithm"); - } - ECPublicKey pk = null; - if ((kf != null) && (encodedKeySpec != null)) { - try { - - pk = (ECPublicKey) kf.generatePublic(encodedKeySpec); - } catch (InvalidKeySpecException e) { - // e.printStackTrace(); - this.error.setError("CE018", "Error casting public key data for JWT signing"); - } - } - return pk; - - } - - - } diff --git a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/PrivateKeyManager.java b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/PrivateKeyManager.java index 5420389..54cae01 100644 --- a/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/PrivateKeyManager.java +++ b/SecurityAPICommons/src/main/java/com/genexus/securityapicommons/keys/PrivateKeyManager.java @@ -12,9 +12,6 @@ import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.EncryptedPrivateKeyInfo; @@ -25,7 +22,6 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMKeyPair; @@ -46,7 +42,6 @@ public class PrivateKeyManager extends com.genexus.securityapicommons.commons.Pr private PrivateKeyInfo privateKeyInfo; private boolean hasPrivateKey; - private String privateKeyAlgorithm; private String encryptionPassword; /** @@ -58,44 +53,93 @@ public PrivateKeyManager() { this.encryptionPassword = null; // Security.addProvider(new BouncyCastleProvider()); } + /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ @Override public boolean load(String privateKeyPath) { - return loadPKCS12(privateKeyPath, "", ""); + + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", privateKeyPath, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + boolean result = loadPKCS12(privateKeyPath, "", ""); + setAlgorithm(); + return result; } @Override public boolean loadEncrypted(String privateKeyPath, String encryptionPassword) { + + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", privateKeyPath, this.error); + SecurityUtils.validateStringInput("password", encryptionPassword, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + this.encryptionPassword = encryptionPassword; - return loadPKCS12(privateKeyPath, "", ""); + boolean result = loadPKCS12(privateKeyPath, "", ""); + setAlgorithm(); + return result; } @Override public boolean loadPKCS12(String privateKeyPath, String alias, String password) { + + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("path", privateKeyPath, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + boolean result = false; try { - loadKeyFromFile(privateKeyPath, alias, password); + result = loadKeyFromFile(privateKeyPath, alias, password); } catch (Exception e) { - this.error.setError("PK018", e.getMessage()); + this.error.setError("PK001", e.getMessage()); return false; } if (this.hasError()) { return false; } - return true; + setAlgorithm(); + return result; } @Override public boolean fromBase64(String base64) { + + this.error.cleanError(); + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateStringInput("base64", base64, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + boolean res; try { res = readBase64(base64); } catch (Exception e) { - this.error.setError("PK0015", e.getMessage()); + this.error.setError("PK002", e.getMessage()); return false; } this.hasPrivateKey = res; + setAlgorithm(); return res; } @@ -106,7 +150,7 @@ public String toBase64() { try { encoded = Base64.toBase64String(this.privateKeyInfo.getEncoded()); } catch (Exception e) { - this.error.setError("PK0017", e.getMessage()); + this.error.setError("PK003", e.getMessage()); return ""; } return encoded; @@ -115,11 +159,7 @@ public String toBase64() { return ""; } - /******** - * EXTERNAL OBJECT PUBLIC METHODS - END - * - * @throws IOException - ********/ + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ private boolean readBase64(String base64) throws IOException { byte[] keybytes = Base64.decode(base64); @@ -128,138 +168,39 @@ private boolean readBase64(String base64) throws IOException { this.privateKeyInfo = PrivateKeyInfo.getInstance(seq); istream.close(); if (this.privateKeyInfo == null) { - this.error.setError("PK015", "Could not read private key from base64 string"); + this.error.setError("PK004", "Could not read private key from base64 string"); return false; } - this.privateKeyAlgorithm = this.privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(); // 1.2.840.113549.1.1.1 return true; } /** * @return PrivateKey type for the key type */ - public PrivateKey getPrivateKeyXML() { - - KeyFactory kf = null; - PKCS8EncodedKeySpec keySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPrivateKeyAlgorithm()); - keySpec = new PKCS8EncodedKeySpec(this.privateKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("PK001", "Error reading algorithm"); - } + public PrivateKey getPrivateKey() { PrivateKey pk = null; - if ((kf != null) && (keySpec != null)) { - try { - pk = kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - this.error.setError("PK002", "Error reading key"); - } - } - return pk; - - } - - /** - * @return PrivateKey type for the key type - */ - public RSAPrivateKey getRSAPrivateKeyJWT() { - - KeyFactory kf = null; - PKCS8EncodedKeySpec keySpec = null; try { - kf = SecurityUtils.getKeyFactory(this.getPrivateKeyAlgorithm()); - keySpec = new PKCS8EncodedKeySpec(this.privateKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("PK001", "Error reading algorithm"); - } - RSAPrivateKey pk = null; - if ((kf != null) && (keySpec != null)) { - try { - pk = (RSAPrivateKey) kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - this.error.setError("PK002", "Error reading key"); - } + KeyFactory kf = SecurityUtils.getKeyFactory(this.getAlgorithm()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(this.privateKeyInfo.getEncoded()); + pk = kf.generatePrivate(keySpec); + } catch (Exception e) { + this.error.setError("PK005", e.getMessage()); + return null; } return pk; } - /** - * Return AsymmetricKeyParameter with private key for the indicated algorithm - * - * @param asymmetricEncryptionAlgorithm AsymmetricEncryptionAlgorithm enum, - * algorithm name - * @return AsymmetricKeyParameter type for encryption, algorithm dependant - */ - public AsymmetricKeyParameter getPrivateKeyParameterForEncryption() { - - if (SecurityUtils.compareStrings(this.getPrivateKeyAlgorithm(), "RSA")) { - return getRSAKeyParameter(); - } else { - - this.error.setError("AE009", "Unrecognized encryption algorithm"); - return null; - } - } - - /** - * @return AsymmetricKeyParameter with private key loaded for RSA or ECDSA for - * signing - */ - public AsymmetricKeyParameter getPrivateKeyParameterForSigning() { - switch (this.getPrivateKeyAlgorithm()) { - case "RSA": - return getRSAKeyParameter(); - case "ECDSA": - AsymmetricKeyParameter parmsECDSA; + @Override + public AsymmetricKeyParameter getAsymmetricKeyParameter() { + AsymmetricKeyParameter akp = null; try { - parmsECDSA = PrivateKeyFactory.createKey(this.privateKeyInfo); - } catch (IOException e) { - this.error.setError("AE007", "Not ECDSA key"); - e.printStackTrace(); + akp = PrivateKeyFactory.createKey(this.privateKeyInfo); + } catch (Exception e) { + this.error.setError("PK006", e.getMessage()); return null; } - return parmsECDSA; - default: - this.error.setError("AE008", "Unrecognized algorithm"); - return null; - } - } - - /** - * @return AsymmetricKeyParameter for RSA with loaded key - */ - private AsymmetricKeyParameter getRSAKeyParameter() { - RSAKeyParameters parms; - try { - parms = (RSAKeyParameters) PrivateKeyFactory.createKey(this.privateKeyInfo); - } catch (IOException e) { - this.error.setError("AE013", "Not RSA key"); - e.printStackTrace(); - return null; - } - return parms; - } - - /** - * @return String certificate's algorithm for signing, 1.2.840.113549.1.1.1 if - * RSA from key pem file - * https://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html - */ - public String getPrivateKeyAlgorithm() { - if (SecurityUtils.compareStrings(this.privateKeyAlgorithm, "1.2.840.113549.1.1.1") - || SecurityUtils.compareStrings(this.privateKeyAlgorithm, "RSA")) { - return "RSA"; - } - if (SecurityUtils.compareStrings(this.privateKeyAlgorithm, "1.2.840.10045.2.1") - || SecurityUtils.compareStrings(this.privateKeyAlgorithm, "EC")) { - return "ECDSA"; - } - return this.privateKeyAlgorithm.toUpperCase(); - + return akp; } /** @@ -312,7 +253,7 @@ private boolean loadPrivateKeyFromFile(String path, String alias, String passwor || SecurityUtils.extensionIs(path, ".jks") || SecurityUtils.extensionIs(path, ".pkcs12")) { return this.hasPrivateKey = loadPrivateKeyFromPKCS12File(path, alias, password); } - this.error.setError("PK014", "Error loading private key"); + this.error.setError("PK007", "Error loading private key"); this.hasPrivateKey = false; return false; } @@ -335,7 +276,7 @@ private boolean loadPrivateKeyFromPKCS12File(String path, String alias, String p NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyStoreException { if (alias == null || password == null) { - this.error.setError("PK004", "Alias and Password are required for PKCS12 keys"); + this.error.setError("PK008", "Alias and Password are required for PKCS12 keys"); return false; } InputStream in = SecurityUtils.inputFileToStream(path); @@ -343,7 +284,6 @@ private boolean loadPrivateKeyFromPKCS12File(String path, String alias, String p ks.load(in, password.toCharArray()); if (ks.getKey(alias, password.toCharArray()) != null) { PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password.toCharArray()); - this.privateKeyAlgorithm = privateKey.getAlgorithm(); this.privateKeyInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); return true; } @@ -363,73 +303,56 @@ private boolean loadPrivateKeyFromPKCS12File(String path, String alias, String p */ private boolean loadPrivateKeyFromPEMFile(String path) throws IOException, CertificateException, PKCSException { boolean flag = false; - FileReader privateKeyReader; - - privateKeyReader = new FileReader(new File(path)); - PEMParser parser = new PEMParser(privateKeyReader); - Object obj; - obj = parser.readObject(); - if (obj instanceof EncryptedPrivateKeyInfo || obj instanceof PKCS8EncryptedPrivateKeyInfo) { - Security.addProvider(new BouncyCastleProvider()); - PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo)obj; - InputDecryptorProvider pkcs8Prov = new JcePKCSPBEInputDecryptorProviderBuilder().setProvider("BC").build(this.encryptionPassword.toCharArray()); - this.privateKeyInfo = encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov); - this.privateKeyAlgorithm = this.privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(); // 1.2.840.113549.1.1.1 - flag = true; - } - if (obj instanceof PrivateKeyInfo) { - this.privateKeyInfo = (PrivateKeyInfo) obj; - this.privateKeyAlgorithm = this.privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(); // 1.2.840.113549.1.1.1 - flag = true; - } - if (obj instanceof PEMKeyPair) { - PEMKeyPair pemKeyPair = (PEMKeyPair) obj; - this.privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); - this.privateKeyAlgorithm = this.privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(); // 1.2.840.113549.1.1.1 - flag = true; - } - if (obj instanceof SubjectPublicKeyInfo) { - this.error.setError("PK008", "The file contains a public key"); - flag = false; - } - if (obj instanceof X509CertificateHolder) { - this.error.setError("PK009", "The file contains a public key"); - flag = false; - } - privateKeyReader.close(); - parser.close(); - if (!flag) { - if (!this.hasError()) { - this.error.setError("PK011", "Error loading private key from pem file"); + try (FileReader privateKeyReader = new FileReader(new File(path))) { + try (PEMParser parser = new PEMParser(privateKeyReader)) { + Object obj; + obj = parser.readObject(); + if (obj instanceof EncryptedPrivateKeyInfo || obj instanceof PKCS8EncryptedPrivateKeyInfo) { + Security.addProvider(new BouncyCastleProvider()); + PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo) obj; + InputDecryptorProvider pkcs8Prov = new JcePKCSPBEInputDecryptorProviderBuilder().setProvider("BC") + .build(this.encryptionPassword.toCharArray()); + this.privateKeyInfo = encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov); + flag = true; + } + if (obj instanceof PrivateKeyInfo) { + this.privateKeyInfo = (PrivateKeyInfo) obj; + flag = true; + } + if (obj instanceof PEMKeyPair) { + PEMKeyPair pemKeyPair = (PEMKeyPair) obj; + this.privateKeyInfo = pemKeyPair.getPrivateKeyInfo(); + flag = true; + } + if (obj instanceof SubjectPublicKeyInfo) { + this.error.setError("PK009", "The file contains a public key"); + flag = false; + } + if (obj instanceof X509CertificateHolder) { + this.error.setError("PK010", "The file contains a public key"); + flag = false; + } } } return flag; } - - /** - * @return PublicKey type for the key type - */ - public ECPrivateKey getECPrivateKeyJWT() { - - KeyFactory kf = null; - PKCS8EncodedKeySpec keySpec = null; - try { - kf = SecurityUtils.getKeyFactory(this.getPrivateKeyAlgorithm()); - keySpec = new PKCS8EncodedKeySpec(this.privateKeyInfo.getEncoded()); - - } catch (NoSuchAlgorithmException | IOException e) { - this.error.setError("PK019", "Error reading algorithm"); + + @Override + protected void setAlgorithm() { + if(this.privateKeyInfo == null) { + return; } - ECPrivateKey pk = null; - if ((kf != null) && (keySpec != null)) { - try { - pk = (ECPrivateKey) kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - this.error.setError("PK020", "Error reading key"); - } + String alg = this.privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(); + switch(alg) + { + case "1.2.840.113549.1.1.1": + this.algorithm = "RSA"; + break; + case "1.2.840.10045.2.1": + this.algorithm = "ECDSA"; + break; } - return pk; - + } } From 2f265a2dd103c2479bd32a918dbf1ac05039feed Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 16 Dec 2022 11:41:33 -0300 Subject: [PATCH 2/9] Update jar versions to 18.2.0 --- GeneXusCryptography/pom.xml | 2 +- GeneXusFtps/pom.xml | 2 +- GeneXusJWT/pom.xml | 2 +- GeneXusSftp/pom.xml | 2 +- GeneXusXmlSignature/pom.xml | 2 +- SecurityAPICommons/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/GeneXusCryptography/pom.xml b/GeneXusCryptography/pom.xml index 15e4ed8..e7cd99f 100644 --- a/GeneXusCryptography/pom.xml +++ b/GeneXusCryptography/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 diff --git a/GeneXusFtps/pom.xml b/GeneXusFtps/pom.xml index a1d7f48..bd0c9fc 100644 --- a/GeneXusFtps/pom.xml +++ b/GeneXusFtps/pom.xml @@ -8,7 +8,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 diff --git a/GeneXusJWT/pom.xml b/GeneXusJWT/pom.xml index 61b11eb..60b717a 100644 --- a/GeneXusJWT/pom.xml +++ b/GeneXusJWT/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 diff --git a/GeneXusSftp/pom.xml b/GeneXusSftp/pom.xml index a638f3a..b7208d9 100644 --- a/GeneXusSftp/pom.xml +++ b/GeneXusSftp/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 diff --git a/GeneXusXmlSignature/pom.xml b/GeneXusXmlSignature/pom.xml index 8791993..3d12c51 100644 --- a/GeneXusXmlSignature/pom.xml +++ b/GeneXusXmlSignature/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 GeneXusXmlSignature diff --git a/SecurityAPICommons/pom.xml b/SecurityAPICommons/pom.xml index 6a1de0c..136d4ae 100644 --- a/SecurityAPICommons/pom.xml +++ b/SecurityAPICommons/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 diff --git a/pom.xml b/pom.xml index 4ec0f98..dbbe4e2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.genexus SecurityAPIParent - 18.0.0 + 18.2.0 pom GeneXusSecurityAPI (Parent) From ff16ffc7a00e3faa280ff7d1f79f0c09f986908a Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 16 Dec 2022 13:40:48 -0300 Subject: [PATCH 3/9] Update jackson libraries to version 2.14.1 --- GeneXusJWT/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GeneXusJWT/pom.xml b/GeneXusJWT/pom.xml index 60b717a..a336d49 100644 --- a/GeneXusJWT/pom.xml +++ b/GeneXusJWT/pom.xml @@ -32,19 +32,19 @@ com.fasterxml.jackson.core jackson-databind - 2.13.2.1 + 2.14.1 com.fasterxml.jackson.core jackson-annotations - 2.13.2 + 2.14.1 com.fasterxml.jackson.core jackson-core - 2.13.2 + 2.14.1 From 12793b6fd01040acbf7e6cd0dfb061cb03d3dcb2 Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 16 Dec 2022 16:02:42 -0300 Subject: [PATCH 4/9] Update commons-net to version 3.9.0 --- GeneXusFtps/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneXusFtps/pom.xml b/GeneXusFtps/pom.xml index bd0c9fc..88154c8 100644 --- a/GeneXusFtps/pom.xml +++ b/GeneXusFtps/pom.xml @@ -37,7 +37,7 @@ commons-net commons-net - 3.3 + 3.9.0 From 338e568503ce1a32aae7333e3c540a71d8b1bf64 Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Thu, 22 Dec 2022 15:47:48 -0300 Subject: [PATCH 5/9] Add remove method on sftpclient --- .../java/com/genexus/sftp/SftpClient.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java b/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java index 52f8f9e..9770fa3 100644 --- a/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java +++ b/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java @@ -94,6 +94,38 @@ public boolean put(String localPath, String remoteDir) { return true; } + public boolean rm(String remotePath) { + String rDir = remotePath; + if (this.channel == null) { + this.error.setError("SF005", "The channel is invalid, reconect"); + return false; + } + + if (remotePath.length() > 1) { + if (remotePath.startsWith("\\") || remotePath.startsWith("/")) { + remotePath = remotePath.substring(1, remotePath.length()); + } + } + try { + this.channel.rm(remotePath); + } catch (SftpException e) { + if (SecurityUtils.compareStrings(rDir, "/") || SecurityUtils.compareStrings(rDir, "\\")) { + try { + this.channel.rm(getFileName(remotePath)); + } catch (SftpException s) { + this.error.setError("SF006", s.getMessage()); + return false; + } + } else { + this.error.setError("SF006", e.getMessage()); + return false; + } + + } + + return true; + } + public boolean get(String remoteFilePath, String localDir) { if (this.whiteList != null) { if (!this.whiteList.isValid(remoteFilePath)) { From b4fdd9a3a0d439d5298fa321ec456d57e39e47cd Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Thu, 22 Dec 2022 15:57:59 -0300 Subject: [PATCH 6/9] Fix error codes --- GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java b/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java index 9770fa3..27bc4ad 100644 --- a/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java +++ b/GeneXusSftp/src/main/java/com/genexus/sftp/SftpClient.java @@ -97,7 +97,7 @@ public boolean put(String localPath, String remoteDir) { public boolean rm(String remotePath) { String rDir = remotePath; if (this.channel == null) { - this.error.setError("SF005", "The channel is invalid, reconect"); + this.error.setError("SF018", "The channel is invalid, reconect"); return false; } @@ -113,11 +113,11 @@ public boolean rm(String remotePath) { try { this.channel.rm(getFileName(remotePath)); } catch (SftpException s) { - this.error.setError("SF006", s.getMessage()); + this.error.setError("SF019", s.getMessage()); return false; } } else { - this.error.setError("SF006", e.getMessage()); + this.error.setError("SF020", e.getMessage()); return false; } From 9f8c97e5d519e1208024141330947d98e8b43037 Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 23 Dec 2022 10:39:45 -0300 Subject: [PATCH 7/9] Fix generic --- .../src/main/java/com/genexus/commons/sftp/SftpClientObject.java | 1 + 1 file changed, 1 insertion(+) diff --git a/GeneXusSftp/src/main/java/com/genexus/commons/sftp/SftpClientObject.java b/GeneXusSftp/src/main/java/com/genexus/commons/sftp/SftpClientObject.java index 1a3d5f0..f5a85f1 100644 --- a/GeneXusSftp/src/main/java/com/genexus/commons/sftp/SftpClientObject.java +++ b/GeneXusSftp/src/main/java/com/genexus/commons/sftp/SftpClientObject.java @@ -12,6 +12,7 @@ public SftpClientObject() { public abstract boolean connect(SftpOptions options); public abstract boolean put(String localPath, String remoteDir); public abstract boolean get(String remoteFilePath, String localDir); + public abstract boolean rm(String remoteFilePath); public abstract void disconnect(); public abstract String getWorkingDirectory(); From f79d6507ed8ac77a1de3f1476b94a8844ee3974a Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Fri, 23 Dec 2022 11:22:10 -0300 Subject: [PATCH 8/9] GeneXusFtps client remove function implementation --- .../commons/ftps/FtpsClientObject.java | 1 + .../java/com/genexus/ftps/FtpsClient.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/GeneXusFtps/src/main/java/com/genexus/commons/ftps/FtpsClientObject.java b/GeneXusFtps/src/main/java/com/genexus/commons/ftps/FtpsClientObject.java index 50e1967..b2c5f1e 100644 --- a/GeneXusFtps/src/main/java/com/genexus/commons/ftps/FtpsClientObject.java +++ b/GeneXusFtps/src/main/java/com/genexus/commons/ftps/FtpsClientObject.java @@ -13,6 +13,7 @@ public FtpsClientObject() public abstract boolean connect(FtpsOptions options); public abstract boolean put(String localPath, String remoteDir); public abstract boolean get(String remoteFilePath, String localDir); + public abstract boolean rm(String remoteFilePath); public abstract void disconnect(); public abstract String getWorkingDirectory(); } diff --git a/GeneXusFtps/src/main/java/com/genexus/ftps/FtpsClient.java b/GeneXusFtps/src/main/java/com/genexus/ftps/FtpsClient.java index 34cb2e5..d074f31 100644 --- a/GeneXusFtps/src/main/java/com/genexus/ftps/FtpsClient.java +++ b/GeneXusFtps/src/main/java/com/genexus/ftps/FtpsClient.java @@ -188,6 +188,38 @@ public boolean get(String remoteFilePath, String localDir) { return true; } + + public boolean rm(String remoteFilePath) { + if (this.client == null || !this.client.isConnected()) { + this.error.setError("FS019", "The connection is invalid, reconect"); + return false; + } + boolean dirchange = true; + try { + if (!isSameDir(getDirectory(remoteFilePath), this.client.printWorkingDirectory())) { + dirchange = this.client.changeWorkingDirectory(getDirectory(remoteFilePath)); + this.pwd = getDirectory(remoteFilePath); + } + + } catch (IOException e2) { + this.error.setError("FS020", "Error changing directory " + e2.getMessage()); + return false; + } + if (!dirchange) { + this.error.setError("FS021", + "Reply code: " + this.client.getReplyCode() + " Reply String: " + this.client.getReplyString()); + return false; + } + boolean deleted = false; + try { + deleted = this.client.deleteFile(remoteFilePath); + } catch (Exception e) { + this.error.setError("FS022", "Error retrieving file " + e.getMessage()); + deleted = false; + } + return deleted; + + } public void disconnect() { if (this.client != null && this.client.isConnected()) { From 6486a2c74a5d9c2ed8a857c8cd098e67b55fc853 Mon Sep 17 00:00:00 2001 From: "ARTECH\\sgrampone" Date: Mon, 20 Mar 2023 15:18:44 -0300 Subject: [PATCH 9/9] Update version for v118u3 to 18.3.0 --- GeneXusCryptography/pom.xml | 2 +- GeneXusFtps/pom.xml | 2 +- GeneXusJWT/pom.xml | 2 +- GeneXusSftp/pom.xml | 2 +- GeneXusXmlSignature/pom.xml | 2 +- SecurityAPICommons/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/GeneXusCryptography/pom.xml b/GeneXusCryptography/pom.xml index e7cd99f..0eb57c5 100644 --- a/GeneXusCryptography/pom.xml +++ b/GeneXusCryptography/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 diff --git a/GeneXusFtps/pom.xml b/GeneXusFtps/pom.xml index 88154c8..c86dbde 100644 --- a/GeneXusFtps/pom.xml +++ b/GeneXusFtps/pom.xml @@ -8,7 +8,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 diff --git a/GeneXusJWT/pom.xml b/GeneXusJWT/pom.xml index a336d49..d66d0a5 100644 --- a/GeneXusJWT/pom.xml +++ b/GeneXusJWT/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 diff --git a/GeneXusSftp/pom.xml b/GeneXusSftp/pom.xml index b7208d9..21f0175 100644 --- a/GeneXusSftp/pom.xml +++ b/GeneXusSftp/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 diff --git a/GeneXusXmlSignature/pom.xml b/GeneXusXmlSignature/pom.xml index 3d12c51..27ee59b 100644 --- a/GeneXusXmlSignature/pom.xml +++ b/GeneXusXmlSignature/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 GeneXusXmlSignature diff --git a/SecurityAPICommons/pom.xml b/SecurityAPICommons/pom.xml index 136d4ae..d711bcf 100644 --- a/SecurityAPICommons/pom.xml +++ b/SecurityAPICommons/pom.xml @@ -7,7 +7,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 diff --git a/pom.xml b/pom.xml index dbbe4e2..0167fab 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.genexus SecurityAPIParent - 18.2.0 + 18.3.0 pom GeneXusSecurityAPI (Parent)