[Pki-devel] [PATCH] 629 Fixed NPE during key-retrieve.

Endi Sukma Dewata edewata at redhat.com
Fri Jul 10 21:05:45 UTC 2015


Keys archived through the KRA connector in CA have null data type
attribute which causes a NPE during retrieval using the key-retrieve
CLI. The SecurityDataRecoveryService has been modified to consider
null data type attribute as asymmetric key type.

The KeyRetrieveCLI and KeyService have been modified to generate
better debugging messages to help troubleshooting.

-- 
Endi S. Dewata
-------------- next part --------------
From c5e734b9d9c9bb1f2b5ddf78e9456685cc891435 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata at redhat.com>
Date: Fri, 10 Jul 2015 16:47:29 -0400
Subject: [PATCH] Fixed NPE during key-retrieve.

Keys archived through the KRA connector in CA have null data type
attribute which causes a NPE during retrieval using the key-retrieve
CLI. The SecurityDataRecoveryService has been modified to consider
null data type attribute as asymmetric key type.

The KeyRetrieveCLI and KeyService have been modified to generate
better debugging messages to help troubleshooting.
---
 .../com/netscape/cmstools/key/KeyRetrieveCLI.java  | 122 +++++++++------------
 .../netscape/kra/SecurityDataRecoveryService.java  |  67 +++++++----
 .../org/dogtagpki/server/kra/rest/KeyService.java  |  37 +++++--
 3 files changed, 123 insertions(+), 103 deletions(-)

diff --git a/base/java-tools/src/com/netscape/cmstools/key/KeyRetrieveCLI.java b/base/java-tools/src/com/netscape/cmstools/key/KeyRetrieveCLI.java
index 5d882f7a6467dabef48c233a467fd54f508dc1ad..92389c021ea060f3c69f8aa69fe962dd9dbbb44f 100644
--- a/base/java-tools/src/com/netscape/cmstools/key/KeyRetrieveCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/key/KeyRetrieveCLI.java
@@ -2,11 +2,9 @@ package com.netscape.cmstools.key;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.util.Arrays;
 
 import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
 
@@ -54,7 +52,7 @@ public class KeyRetrieveCLI extends CLI {
         options.addOption(option);
     }
 
-    public void execute(String[] args) {
+    public void execute(String[] args) throws Exception {
         // Always check for "--help" prior to parsing
         if (Arrays.asList(args).contains("--help")) {
             // Display usage
@@ -81,95 +79,73 @@ public class KeyRetrieveCLI extends CLI {
             System.exit(-1);
         }
 
-        if(cmd.getOptions().length==0){
+        if (cmd.getOptions().length == 0) {
             System.err.println("Error: Incorrect number of parameters provided.");
             printHelp();
             System.exit(-1);
         }
+
         String requestFile = cmd.getOptionValue("input");
 
         Key keyData = null;
 
         if (requestFile != null) {
-            try {
-                JAXBContext context = JAXBContext.newInstance(KeyRecoveryRequest.class);
-                Unmarshaller unmarshaller = context.createUnmarshaller();
-                FileInputStream fis = new FileInputStream(requestFile);
-                KeyRecoveryRequest req = (KeyRecoveryRequest) unmarshaller.unmarshal(fis);
+            JAXBContext context = JAXBContext.newInstance(KeyRecoveryRequest.class);
+            Unmarshaller unmarshaller = context.createUnmarshaller();
+            FileInputStream fis = new FileInputStream(requestFile);
+            KeyRecoveryRequest req = (KeyRecoveryRequest) unmarshaller.unmarshal(fis);
 
-                if (req.getKeyId() == null) {
-                    System.err.println("Error: Key Id must be specified in the request file.");
-                    System.exit(-1);
-                }
-                if (req.getCertificate() != null) {
-                    keyData = keyCLI.keyClient.retrieveKeyByPKCS12(req.getKeyId(), req.getCertificate(),
-                            req.getPassphrase());
-                } else if (req.getPassphrase() != null) {
-                    keyData = keyCLI.keyClient.retrieveKeyByPassphrase(req.getKeyId(), req.getPassphrase());
-                } else if (req.getSessionWrappedPassphrase() != null) {
-                    keyData = keyCLI.keyClient.retrieveKeyUsingWrappedPassphrase(req.getKeyId(),
-                            Utils.base64decode(req.getTransWrappedSessionKey()),
-                            Utils.base64decode(req.getSessionWrappedPassphrase()),
-                            Utils.base64decode(req.getNonceData()));
-                } else if (req.getTransWrappedSessionKey() != null) {
-                    keyData = keyCLI.keyClient.retrieveKey(req.getKeyId(),
-                            Utils.base64decode(req.getTransWrappedSessionKey()));
-                } else {
-                    keyData = keyCLI.keyClient.retrieveKey(req.getKeyId());
-                }
-            } catch (JAXBException e) {
-                System.err.println("Error: Cannot parse the request file.");
-                if (verbose)
-                    e.printStackTrace();
-                System.exit(-1);
-            } catch (FileNotFoundException e) {
-                System.err.println("Error: Cannot locate file at path: " + requestFile);
-                if (verbose)
-                    e.printStackTrace();
-                System.exit(-1);
-            } catch (Exception e) {
-                System.err.println(e.getMessage());
-                if (verbose)
-                    e.printStackTrace();
+            if (req.getKeyId() == null) {
+                System.err.println("Error: Key ID must be specified in the request file.");
                 System.exit(-1);
             }
 
+            if (req.getCertificate() != null) {
+                keyData = keyCLI.keyClient.retrieveKeyByPKCS12(req.getKeyId(), req.getCertificate(),
+                        req.getPassphrase());
+
+            } else if (req.getPassphrase() != null) {
+                keyData = keyCLI.keyClient.retrieveKeyByPassphrase(req.getKeyId(), req.getPassphrase());
+
+            } else if (req.getSessionWrappedPassphrase() != null) {
+                keyData = keyCLI.keyClient.retrieveKeyUsingWrappedPassphrase(req.getKeyId(),
+                        Utils.base64decode(req.getTransWrappedSessionKey()),
+                        Utils.base64decode(req.getSessionWrappedPassphrase()),
+                        Utils.base64decode(req.getNonceData()));
+
+            } else if (req.getTransWrappedSessionKey() != null) {
+                keyData = keyCLI.keyClient.retrieveKey(req.getKeyId(),
+                        Utils.base64decode(req.getTransWrappedSessionKey()));
+
+            } else {
+                keyData = keyCLI.keyClient.retrieveKey(req.getKeyId());
+            }
+
         } else {
             // Using command line options.
             String keyId = cmd.getOptionValue("keyID");
             String passphrase = cmd.getOptionValue("passphrase");
-            try {
-                if (passphrase != null) {
-                    keyData = keyCLI.keyClient.retrieveKeyByPassphrase(new KeyId(keyId), passphrase);
-                } else {
-                    keyData = keyCLI.keyClient.retrieveKey(new KeyId(keyId));
-                    clientEncryption = false;
 
-                    // No need to return the encrypted data since encryption
-                    //is done locally.
-                    keyData.setEncryptedData(null);
-                }
-            } catch (Exception e) {
-                System.err.println(e.getMessage());
-                if (verbose)
-                    e.printStackTrace();
-                System.exit(-1);
+            if (passphrase != null) {
+                keyData = keyCLI.keyClient.retrieveKeyByPassphrase(new KeyId(keyId), passphrase);
+
+            } else {
+                keyData = keyCLI.keyClient.retrieveKey(new KeyId(keyId));
+                clientEncryption = false;
+
+                // No need to return the encrypted data since encryption
+                // is done locally.
+                keyData.setEncryptedData(null);
             }
         }
 
         String outputFilePath = cmd.getOptionValue("output");
         if (outputFilePath != null) {
-            try {
-                JAXBContext context = JAXBContext.newInstance(Key.class);
-                Marshaller marshaller = context.createMarshaller();
-                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
-                marshaller.marshal(keyData, new File(outputFilePath));
-            } catch (JAXBException e) {
-                System.err.println(e.getMessage());
-                if (verbose)
-                    e.printStackTrace();
-                System.exit(-1);
-            }
+            JAXBContext context = JAXBContext.newInstance(Key.class);
+            Marshaller marshaller = context.createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            marshaller.marshal(keyData, new File(outputFilePath));
+
         } else {
             MainCLI.printMessage("Retrieve Key Information");
             printKeyData(keyData);
@@ -180,10 +156,14 @@ public class KeyRetrieveCLI extends CLI {
         System.out.println("  Key Algorithm: " + key.getAlgorithm());
         System.out.println("  Key Size: " + key.getSize());
         System.out.println("  Nonce data: " + Utils.base64encode(key.getNonceData()));
-        if(clientEncryption)
+
+        if (clientEncryption) {
             System.out.println("  Encrypted Data:" + Utils.base64encode(key.getEncryptedData()));
-        if (!clientEncryption)
+
+        } else {
             System.out.println("  Actual archived data: " + Utils.base64encode(key.getData()));
+        }
+
         if (key.getP12Data() != null) {
             System.out.println("  Key data in PKCS12 format: " + key.getP12Data());
         }
diff --git a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
index 752c8dff5f38e43c1961af209b99331c443c974a..b2449677f455acb55a4b386b305232bf54a4d1a9 100644
--- a/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
+++ b/base/kra/src/com/netscape/kra/SecurityDataRecoveryService.java
@@ -117,6 +117,8 @@ public class SecurityDataRecoveryService implements IService {
     public boolean serviceRequest(IRequest request)
             throws EBaseException {
 
+        CMS.debug("SecurityDataRecoveryService.serviceRequest()");
+
         //Pave the way for allowing generated IV vector
         byte iv[]= null;
         byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 };
@@ -130,28 +132,34 @@ public class SecurityDataRecoveryService implements IService {
         BigInteger serialno = request.getExtDataInBigInteger(ATTR_SERIALNO);
         request.setExtData(ATTR_KEY_RECORD, serialno);
         RequestId requestID = request.getRequestId();
+
         if (params == null) {
-            CMS.debug("Can't get volatile params.");
+            CMS.debug("SecurityDataRecoveryService: Can't get volatile params.");
             auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
                     "cannot get volatile params");
             throw new EBaseException("Can't obtain volatile params!");
         }
-        byte[] wrappedPassPhrase = null;
-        byte[] wrappedSessKey = null;
+
         String transWrappedSessKeyStr = (String) params.get(IRequest.SECURITY_DATA_TRANS_SESS_KEY);
+        byte[] wrappedSessKey = null;
         if (transWrappedSessKeyStr != null) {
             wrappedSessKey = Utils.base64decode(transWrappedSessKeyStr);
         }
+
         String sessWrappedPassPhraseStr = (String) params.get(IRequest.SECURITY_DATA_SESS_PASS_PHRASE);
+        byte[] wrappedPassPhrase = null;
         if (sessWrappedPassPhraseStr != null) {
             wrappedPassPhrase = Utils.base64decode(sessWrappedPassPhraseStr);
         }
+
         String ivInStr = (String) params.get(IRequest.SECURITY_DATA_IV_STRING_IN);
         if (ivInStr != null) {
             iv_in = Utils.base64decode(ivInStr);
         }
+
         if (transWrappedSessKeyStr == null && sessWrappedPassPhraseStr == null) {
             //We may be in recovery case where no params were initially submitted.
+            CMS.debug("SecurityDataRecoveryService: No params provided.");
             return false;
         }
 
@@ -168,35 +176,43 @@ public class SecurityDataRecoveryService implements IService {
 
         KeyRecord keyRecord = (KeyRecord) mStorage.readKeyRecord(serialno);
 
-        SymmetricKey unwrappedSess = null;
         String dataType = (String) keyRecord.get(IKeyRecord.ATTR_DATA_TYPE);
+        if (dataType == null) dataType = KeyRequestResource.ASYMMETRIC_KEY_TYPE;
+
+        SymmetricKey unwrappedSess = null;
         SymmetricKey symKey = null;
         byte[] unwrappedSecData = null;
         PrivateKey privateKey = null;
+
         if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
             symKey = recoverSymKey(keyRecord);
 
         } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
             unwrappedSecData = recoverSecurityData(keyRecord);
+
         } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
             try {
                 privateKey = mStorageUnit.unwrap(keyRecord.getPrivateKeyData(),
                         X509Key.parsePublicKey(new DerValue(keyRecord.getPublicKeyData())));
+
             } catch (IOException e) {
-                e.printStackTrace();
-                CMS.debug("Cannot unwrap stored private key.");
-                throw new EBaseException("Cannot fetch the private key from the database.");
+                throw new EBaseException("Cannot fetch the private key from the database.", e);
             }
+
         } else {
             throw new EBaseException("Invalid data type stored in the database.");
         }
+
         CryptoToken ct = mTransportUnit.getToken();
 
         byte[] key_data = null;
         String pbeWrappedData = null;
-        if (sessWrappedPassPhraseStr != null) { //We have a trans wrapped pass phrase, we will be doing PBE packaging
+
+        if (sessWrappedPassPhraseStr != null) {
+            CMS.debug("SecurityDataRecoveryService: secure retrieved data with tranport passphrase");
             byte[] unwrappedPass = null;
             Password pass = null;
+
             try {
                 unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.DECRYPT);
                 Cipher decryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
@@ -207,12 +223,15 @@ public class SecurityDataRecoveryService implements IService {
                 passStr = null;
 
                 if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
+                    CMS.debug("SecurityDataRecoveryService: wrap stored symmetric key with transport passphrase");
                     pbeWrappedData = createEncryptedContentInfo(ct, symKey, null, null,
                             pass);
                 } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)){
+                    CMS.debug("SecurityDataRecoveryService: encrypt stored passphrase with transport passphrase");
                     pbeWrappedData = createEncryptedContentInfo(ct, null, unwrappedSecData, null,
                             pass);
                 } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
+                    CMS.debug("SecurityDataRecoveryService: wrap stored private key with transport passphrase");
                     pbeWrappedData = createEncryptedContentInfo(ct, null, null, privateKey,
                             pass);
                 }
@@ -222,73 +241,81 @@ public class SecurityDataRecoveryService implements IService {
             } catch (Exception e) {
                 auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
                         "Cannot unwrap passphrase");
-                throw new EBaseException("Can't unwrap pass phase! " + e.toString());
+                throw new EBaseException("Cannot unwrap passphrase: " + e, e);
+
             } finally {
-                if ( pass != null) {
+                if (pass != null) {
                     pass.clear();
                 }
 
-                if ( unwrappedPass != null) {
+                if (unwrappedPass != null) {
                     java.util.Arrays.fill(unwrappedPass, (byte) 0);
                 }
             }
 
-        } else { // No trans wrapped pass phrase, return session wrapped data.
+        } else {
+            CMS.debug("SecurityDataRecoveryService: secure retrieved data with session key");
+
             if (dataType.equals(KeyRequestResource.SYMMETRIC_KEY_TYPE)) {
-                //wrap the key with session key
+                CMS.debug("SecurityDataRecoveryService: wrap stored symmetric key with session key");
                 try {
                     unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.WRAP);
                     KeyWrapper wrapper = ct.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
                     wrapper.initWrap(unwrappedSess, new IVParameterSpec(iv));
                     key_data = wrapper.wrap(symKey);
+
                 } catch (Exception e) {
                     auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
                             "Cannot wrap symmetric key");
-                    throw new EBaseException("Can't wrap symmetric key! " + e.toString());
+                    throw new EBaseException("Cannot wrap symmetric key: " + e, e);
                 }
 
             } else if (dataType.equals(KeyRequestResource.PASS_PHRASE_TYPE)) {
+                CMS.debug("SecurityDataRecoveryService: encrypt stored passphrase with session key");
                 try {
                     unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.ENCRYPT);
                     Cipher encryptor = ct.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD);
                     if (encryptor != null) {
                         encryptor.initEncrypt(unwrappedSess, new IVParameterSpec(iv));
                         key_data = encryptor.doFinal(unwrappedSecData);
+
                     } else {
                         auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID,
                                 serialno.toString(), "Failed to create cipher");
                         throw new IOException("Failed to create cipher");
                     }
+
                 } catch (Exception e) {
-                    e.printStackTrace();
                     auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID,
-                            serialno.toString(), "Cannot wrap pass phrase");
-                    throw new EBaseException("Can't wrap pass phrase!");
+                            serialno.toString(), "Cannot encrypt passphrase");
+                    throw new EBaseException("Cannot encrypt passphrase: " + e, e);
                 }
 
             } else if (dataType.equals(KeyRequestResource.ASYMMETRIC_KEY_TYPE)) {
-                CMS.debug("Wrapping the private key with the session key");
+                CMS.debug("SecurityDataRecoveryService: wrap stored private key with session key");
                 try {
                     unwrappedSess = mTransportUnit.unwrap_sym(wrappedSessKey, SymmetricKey.Usage.WRAP);
                     KeyWrapper wrapper = ct.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
                     wrapper.initWrap(unwrappedSess, new IVParameterSpec(iv));
                     key_data = wrapper.wrap(privateKey);
+
                 } catch (Exception e) {
                     auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(),
                             "Cannot wrap private key");
-                    throw new EBaseException("Cannot wrap private key - " + e.toString());
+                    throw new EBaseException("Cannot wrap private key: " + e, e);
                 }
             }
 
             String wrappedKeyData = Utils.base64encode(key_data);
             params.put(IRequest.SECURITY_DATA_SESS_WRAPPED_DATA, wrappedKeyData);
             params.put(IRequest.SECURITY_DATA_IV_STRING_OUT, ivStr);
-
         }
+
         auditRecoveryRequestProcessed(auditSubjectID, ILogger.SUCCESS, requestID, serialno.toString(),
                 "None");
         request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS);
         mKRA.getRequestQueue().updateRequest(request);
+
         return false; //return true ? TODO
     }
 
diff --git a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
index 99e6471b197b160ff91ba91cb8d6e2c537073e1f..f4445bb65d837b840422462b6fcaf6688632dc6e 100644
--- a/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
+++ b/base/kra/src/org/dogtagpki/server/kra/rest/KeyService.java
@@ -117,53 +117,66 @@ public class KeyService extends PKIService implements KeyResource {
      */
     @Override
     public Response retrieveKey(KeyRecoveryRequest data) {
-        String method = "KeyService.retrieveKey: ";
+
+        CMS.debug("KeyService.retrieveKey()");
         String auditInfo = "KeyService.retrieveKey";
-        CMS.debug(method + "begins.");
+
         if (data == null) {
-            String msg = "Invalid request: data is null";
-            CMS.debug(msg);
-            auditRetrieveKey(ILogger.FAILURE, "None", "None", auditInfo + ";" + msg);
-            throw new BadRequestException(method + msg);
+            String message = "Missing key recovery request";
+            CMS.debug(message);
+            auditRetrieveKey(ILogger.FAILURE, "None", "None", auditInfo + ";" + message);
+            throw new BadRequestException(message);
         }
-        // auth and authz
+
         RequestId requestID = data.getRequestId();
-        IRequest request;
-        KeyId keyId = data.getKeyId();
+        CMS.debug("KeyService: request ID: " + requestID);
 
         if (requestID != null)
             auditInfo = auditInfo + ": requestID=" + requestID.toString();
 
+        KeyId keyId = data.getKeyId();
+        CMS.debug("KeyService: key ID: " + keyId);
         if (keyId != null)
             auditInfo = auditInfo + "; keyID=" + keyId.toString();
 
+        IRequest request;
         try {
             request = queue.findRequest(requestID);
+
         } catch (EBaseException e) {
-            e.printStackTrace();
+            CMS.debug(e);
             auditRetrieveKey(ILogger.FAILURE, requestID, null, auditInfo + ";" + e.getMessage());
             throw new PKIException(e.getMessage());
         }
+
         String type = request.getRequestType();
+        CMS.debug("KeyService: request type: " + type);
         auditInfo = auditInfo + "; request type:" + type;
+
         KeyData keyData;
         try {
             if (IRequest.KEYRECOVERY_REQUEST.equals(type)) {
                 keyData = recoverKey(data);
+
             } else {
                 keyId = validateRequest(data);
                 keyData = getKey(keyId, data);
             }
+
         } catch (Exception e) {
-            e.printStackTrace();
+            CMS.debug(e);
             auditRetrieveKey(ILogger.FAILURE, requestID, keyId, auditInfo + ";" + e.getMessage());
             throw new PKIException(e.getMessage());
         }
+
         if (keyData == null) {
-            // no key record
+            CMS.debug("KeyService: No key record");
             auditRetrieveKey(ILogger.FAILURE, requestID, keyId, auditInfo + "; No key record");
             throw new HTTPGoneException("No key record.");
         }
+
+        CMS.debug("KeyService: key retrieved");
+
         auditRetrieveKey(ILogger.SUCCESS, requestID, keyId, auditInfo);
 
         return createOKResponse(keyData);
-- 
1.9.3



More information about the Pki-devel mailing list