diff options
| author | Ade Lee <alee@redhat.com> | 2017-03-15 23:05:07 -0400 |
|---|---|---|
| committer | Ade Lee <alee@redhat.com> | 2017-03-15 23:05:07 -0400 |
| commit | 080f3d2a8bf36be407c79ddd71381450c8667b2e (patch) | |
| tree | 58594f9c45e88c882579d9f6638ff6639e506729 | |
| parent | 764a17314e81cade8bf1192739b5a2fad11d18bd (diff) | |
| parent | 07135b5906f97a8c68148a07484e63d6896f410b (diff) | |
| download | pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.gz pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.tar.xz pki-080f3d2a8bf36be407c79ddd71381450c8667b2e.zip | |
Merge branch 'master' of github.com:dogtagpki/pki
63 files changed, 5149 insertions, 1506 deletions
diff --git a/base/ca/src/org/dogtagpki/server/ca/rest/CertService.java b/base/ca/src/org/dogtagpki/server/ca/rest/CertService.java index 2f9f46729..ebbab2572 100644 --- a/base/ca/src/org/dogtagpki/server/ca/rest/CertService.java +++ b/base/ca/src/org/dogtagpki/server/ca/rest/CertService.java @@ -64,6 +64,7 @@ import com.netscape.certsrv.dbs.certdb.CertId; import com.netscape.certsrv.dbs.certdb.ICertRecord; import com.netscape.certsrv.dbs.certdb.ICertRecordList; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; import com.netscape.certsrv.logging.AuditFormat; import com.netscape.certsrv.logging.ILogger; import com.netscape.certsrv.request.IRequest; @@ -80,8 +81,11 @@ import netscape.security.pkcs.PKCS7; import netscape.security.pkcs.SignerInfo; import netscape.security.provider.RSAPublicKey; import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; import netscape.security.x509.RevocationReason; import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509ExtensionException; import netscape.security.x509.X509Key; /** @@ -529,6 +533,20 @@ public class CertService extends PKIService implements CertResource { certData.setRevokedOn(record.getRevokedOn()); certData.setRevokedBy(record.getRevokedBy()); + IRevocationInfo revInfo = record.getRevocationInfo(); + if (revInfo != null) { + CRLExtensions revExts = revInfo.getCRLEntryExtensions(); + if (revExts != null) { + try { + CRLReasonExtension ext = (CRLReasonExtension) + revExts.get(CRLReasonExtension.NAME); + certData.setRevocationReason(ext.getReason().getCode()); + } catch (X509ExtensionException e) { + // nothing to do + } + } + } + certData.setStatus(record.getStatus()); if (authority.noncesEnabled() && generateNonce) { diff --git a/base/common/python/pki/cli/main.py b/base/common/python/pki/cli/main.py new file mode 100644 index 000000000..53e1b893a --- /dev/null +++ b/base/common/python/pki/cli/main.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# Authors: +# Endi S. Dewata <edewata@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2014 Red Hat, Inc. +# All rights reserved. +# + +from __future__ import absolute_import +from __future__ import print_function +import shlex +import subprocess +import sys +import traceback + +import pki.cli +import pki.cli.pkcs12 + + +PYTHON_COMMANDS = ['pkcs12-import'] + + +class PKICLI(pki.cli.CLI): + + def __init__(self): + super(PKICLI, self).__init__( + 'pki', 'PKI command-line interface') + + self.database = None + self.password = None + self.password_file = None + self.token = None + + self.add_module(pki.cli.pkcs12.PKCS12CLI()) + + def get_full_module_name(self, module_name): + return module_name + + def print_help(self): + print('Usage: pki [OPTIONS]') + print() + print(' --client-type <type> PKI client type (default: java)') + print(' -d <path> Client security database location ' + + '(default: ~/.dogtag/nssdb)') + print(' -c <password> Client security database password ' + + '(mutually exclusive to the -C option)') + print(' -C <path> Client-side password file ' + + '(mutually exclusive to the -c option)') + print(' --token <name> Security token name') + print() + print(' -v, --verbose Run in verbose mode.') + print(' --debug Show debug messages.') + print(' --help Show help message.') + print() + + super(PKICLI, self).print_help() + + def execute_java(self, args, stdout=sys.stdout): + + # read Java home + value = subprocess.check_output( + '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $JAVA_HOME', + shell=True) + java_home = value.decode(sys.getfilesystemencoding()).strip() + + # read PKI library + value = subprocess.check_output( + '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_LIB', + shell=True) + pki_lib = value.decode(sys.getfilesystemencoding()).strip() + + # read logging configuration path + value = subprocess.check_output( + '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $LOGGING_CONFIG', + shell=True) + logging_config = value.decode(sys.getfilesystemencoding()).strip() + + cmd = [ + java_home + '/bin/java', + '-Djava.ext.dirs=' + pki_lib, + '-Djava.util.logging.config.file=' + logging_config, + 'com.netscape.cmstools.cli.MainCLI' + ] + + # restore options for Java commands + + if self.database: + cmd.extend(['-d', self.database]) + + if self.password: + cmd.extend(['-c', self.password]) + + if self.password_file: + cmd.extend(['-C', self.password_file]) + + if self.token and self.token != 'internal': + cmd.extend(['--token', self.token]) + + if self.verbose: + cmd.extend(['--verbose']) + + cmd.extend(args) + + if self.verbose: + print('Java command: %s' % ' '.join(cmd)) + + subprocess.check_call(cmd, stdout=stdout) + + def execute(self, argv): + + # append global options + value = subprocess.check_output( + '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_CLI_OPTIONS', + shell=True) + value = value.decode(sys.getfilesystemencoding()).strip() + args = shlex.split(value) + args.extend(argv[1:]) + + client_type = 'java' + + pki_options = [] + command = None + cmd_args = [] + + # read pki options before the command + # remove options for Python module + + i = 0 + while i < len(args): + # if arg is a command, stop + if args[i][0] != '-': + command = args[i] + break + + # get database path + if args[i] == '-d': + self.database = args[i + 1] + pki_options.append(args[i]) + pki_options.append(args[i + 1]) + i = i + 2 + + # get database password + elif args[i] == '-c': + self.password = args[i + 1] + pki_options.append(args[i]) + pki_options.append(args[i + 1]) + i = i + 2 + + # get database password file path + elif args[i] == '-C': + self.password_file = args[i + 1] + pki_options.append(args[i]) + pki_options.append(args[i + 1]) + i = i + 2 + + # get token name + elif args[i] == '--token': + self.token = args[i + 1] + pki_options.append(args[i]) + pki_options.append(args[i + 1]) + i = i + 2 + + # check verbose option + elif args[i] == '-v' or args[i] == '--verbose': + self.set_verbose(True) + pki_options.append(args[i]) + i = i + 1 + + # check debug option + elif args[i] == '--debug': + self.set_verbose(True) + self.set_debug(True) + pki_options.append(args[i]) + i = i + 1 + + # get client type + elif args[i] == '--client-type': + client_type = args[i + 1] + pki_options.append(args[i]) + pki_options.append(args[i + 1]) + i = i + 2 + + else: # otherwise, save the arg for the next module + cmd_args.append(args[i]) + i = i + 1 + + # save the rest of the args + while i < len(args): + cmd_args.append(args[i]) + i = i + 1 + + if self.verbose: + print('PKI options: %s' % ' '.join(pki_options)) + print('PKI command: %s %s' % (command, ' '.join(cmd_args))) + + if client_type == 'python' or command in PYTHON_COMMANDS: + (module, module_args) = self.parse_args(cmd_args) + module.execute(module_args) + + elif client_type == 'java': + self.execute_java(cmd_args) + + else: + raise Exception('Unsupported client type: ' + client_type) + + +if __name__ == '__main__': + + cli = PKICLI() + + try: + cli.execute(sys.argv) + + except subprocess.CalledProcessError as e: + if cli.verbose: + print('ERROR: %s' % e) + elif cli.debug: + traceback.print_exc() + sys.exit(e.returncode) + + except KeyboardInterrupt: + print() + sys.exit(-1) diff --git a/base/common/python/pki/util.py b/base/common/python/pki/util.py index 8a75ff6f5..68118f439 100644 --- a/base/common/python/pki/util.py +++ b/base/common/python/pki/util.py @@ -143,6 +143,39 @@ def customize_file(input_file, output_file, params): outfile.write(line) +def load_properties(filename, properties): + + with open(filename) as f: + + lines = f.read().splitlines() + + for index, line in enumerate(lines): + + line = line.strip() + + if not line or line.startswith('#'): + continue + + parts = line.split('=', 1) + + if len(parts) < 2: + raise Exception('Missing delimiter in %s line %d' % + (filename, index + 1)) + + name = parts[0].strip() + value = parts[1].strip() + properties[name] = value + + +def store_properties(filename, properties): + + with open(filename, 'w') as f: + + for name, value in properties.items(): + line = '%s=%s\n' % (name, value) + f.write(line) + + def copytree(src, dst, symlinks=False, ignore=None): """ Recursively copy a directory tree using copy2(). diff --git a/base/common/src/com/netscape/certsrv/authentication/EInvalidCredentials.java b/base/common/src/com/netscape/certsrv/authentication/EInvalidCredentials.java index a562d69e5..f6d8e2d77 100644 --- a/base/common/src/com/netscape/certsrv/authentication/EInvalidCredentials.java +++ b/base/common/src/com/netscape/certsrv/authentication/EInvalidCredentials.java @@ -35,4 +35,8 @@ public class EInvalidCredentials extends EAuthException { public EInvalidCredentials(String errorString) { super(errorString); } + + public EInvalidCredentials(String errorString, Exception cause) { + super(errorString, cause); + } } diff --git a/base/common/src/com/netscape/certsrv/cert/CertData.java b/base/common/src/com/netscape/certsrv/cert/CertData.java index bb6d4c07c..1e9ce04eb 100644 --- a/base/common/src/com/netscape/certsrv/cert/CertData.java +++ b/base/common/src/com/netscape/certsrv/cert/CertData.java @@ -71,6 +71,7 @@ public class CertData { String status; Date revokedOn; String revokedBy; + Integer revocationReason; Long nonce; @@ -186,6 +187,15 @@ public class CertData { this.revokedBy = revokedBy; } + @XmlElement(name="RevocationReason") + public Integer getRevocationReason() { + return revocationReason; + } + + public void setRevocationReason(Integer revocationReason) { + this.revocationReason = revocationReason; + } + @XmlElement(name="Link") public Link getLink() { return link; diff --git a/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java b/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java index f66d53f1e..163d4dd5d 100644 --- a/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java +++ b/base/common/src/com/netscape/certsrv/dbs/keydb/IKeyRecord.java @@ -22,6 +22,7 @@ import java.util.Date; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.security.WrappingParams; /** * An interface contains constants for key record. @@ -167,4 +168,8 @@ public interface IKeyRecord { * @exception EBaseException failed to retrieve authorization realm */ public String getRealm() throws EBaseException; + + public void setWrappingParams(WrappingParams params) throws Exception; + + public WrappingParams getWrappingParams(WrappingParams oldParams) throws Exception; } diff --git a/base/common/src/com/netscape/certsrv/key/KeyRecoveryRequest.java b/base/common/src/com/netscape/certsrv/key/KeyRecoveryRequest.java index 31a2c5005..26cf766a8 100644 --- a/base/common/src/com/netscape/certsrv/key/KeyRecoveryRequest.java +++ b/base/common/src/com/netscape/certsrv/key/KeyRecoveryRequest.java @@ -45,6 +45,8 @@ public class KeyRecoveryRequest extends ResourceMessage { private static final String NONCE_DATA = "nonceData"; private static final String CERTIFICATE = "certificate"; private static final String PASSPHRASE = "passphrase"; + private static final String PAYLOAD_ENCRYPTION_OID = "payloadEncryptionOID"; + private static final String PAYLOAD_WRAPPING_NAME = "payloadWrappingName"; public KeyRecoveryRequest() { // required for JAXB (defaults) @@ -177,6 +179,34 @@ public class KeyRecoveryRequest extends ResourceMessage { attributes.put(PASSPHRASE, passphrase); } + /** + * @return the payloadEncryptionOID + */ + public String getPaylodEncryptionOID() { + return attributes.get(PAYLOAD_ENCRYPTION_OID); + } + + /** + * @param payloadEncryptionOID the payloadEncryptionOID to set + */ + public void setPayloadEncryptionOID(String payloadEncryptionOID) { + attributes.put(PAYLOAD_ENCRYPTION_OID, payloadEncryptionOID); + } + + /** + * @return the payloadWrappingName + */ + public String getPayloadWrappingName() { + return attributes.get(PAYLOAD_WRAPPING_NAME); + } + + /** + * @param payloadWrappingName the payloadWrappingName to set + */ + public void setPayloadWrappingName(String payloadWrappingName) { + attributes.put(PAYLOAD_WRAPPING_NAME, payloadWrappingName); + } + public static KeyRecoveryRequest valueOf(String string) throws Exception { try { return ResourceMessage.unmarshal(string, KeyRecoveryRequest.class); diff --git a/base/common/src/com/netscape/certsrv/request/IRequest.java b/base/common/src/com/netscape/certsrv/request/IRequest.java index 29b1bbb87..94fd2fd3f 100644 --- a/base/common/src/com/netscape/certsrv/request/IRequest.java +++ b/base/common/src/com/netscape/certsrv/request/IRequest.java @@ -179,6 +179,8 @@ public interface IRequest extends Serializable { public static final String SECURITY_DATA_IV_STRING_OUT = "iv_out"; public static final String SECURITY_DATA_SESS_WRAPPED_DATA = "sessWrappedSecData"; public static final String SECURITY_DATA_PASS_WRAPPED_DATA = "passPhraseWrappedData"; + public static final String SECURITY_DATA_PL_ENCRYPTION_OID = "payloadEncryptionOID"; + public static final String SECURITY_DATA_PL_WRAPPING_NAME = "payloadWrappingName"; // key generation request attributes public static final String ASYMKEY_GENERATION_REQUEST = "asymkeyGenRequest"; diff --git a/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java b/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java index 7f5e95ec3..abb5f11a2 100644 --- a/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java +++ b/base/common/src/com/netscape/certsrv/security/IEncryptionUnit.java @@ -22,7 +22,6 @@ import java.security.PublicKey; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SymmetricKey; -import org.mozilla.jss.crypto.SymmetricKey.Type; import com.netscape.certsrv.base.EBaseException; @@ -41,26 +40,6 @@ public interface IEncryptionUnit extends IToken { public PublicKey getPublicKey(); /** - * Wraps data. The given key will be wrapped by the - * private key in this unit. - * - * @param priKey private key to be wrapped - * @return wrapped data - * @exception EBaseException failed to wrap - */ - public byte[] wrap(PrivateKey priKey) throws Exception; - - /** - * Wraps data. The given key will be wrapped by the - * private key in this unit. - * - * @param symKey symmetric key to be wrapped - * @return wrapped data - * @exception EBaseException failed to wrap - */ - public byte[] wrap(SymmetricKey symKey) throws Exception; - - /** * Verifies the given key pair. * * @param publicKey public key @@ -70,143 +49,19 @@ public interface IEncryptionUnit extends IToken { EBaseException; /** - * Unwraps data. This method rebuilds the private key by - * unwrapping the private key data. - * - * @param sessionKey session key that unwrap the private key - * @param symmAlgOID symmetric algorithm - * @param symmAlgParams symmetric algorithm parameters - * @param privateKey private key data - * @param pubKey public key - * @return private key object - * @throws Exception - */ - public PrivateKey unwrap(byte sessionKey[], String symmAlgOID, - byte symmAlgParams[], byte privateKey[], - PublicKey pubKey) - throws Exception; - - /** - * Unwraps data. This method rebuilds the private key by - * unwrapping the private key data. - * - * @param symmAlgOID symmetric algorithm - * @param symmAlgParams symmetric algorithm parameters - * @param pubKey public key - * @param transportCert transport certificate - * @return private key object - * @throws Exception - */ - public PrivateKey unwrap(byte encSymmKey[], String symmAlgOID, - byte symmAlgParams[], byte encValue[], PublicKey pubKey, - org.mozilla.jss.crypto.X509Certificate transportCert) - throws Exception; - - /** - * Unwraps symmetric key data. This method rebuilds the symmetric key by - * unwrapping the private data blob. - * - * @param wrappedKeyData symmetric key data wrapped up with session key - * @return Symmetric key object - * @exception Exception failed to unwrap - */ - - public SymmetricKey unwrap(byte wrappedKeyData[], SymmetricKey.Type algorithm, int keySize) - throws Exception; - - /** - * Unwraps symmetric key . This method - * unwraps the symmetric key. - * - * @param sessionKey session key that unwrap the symmetric key - * @param symmAlgOID symmetric algorithm - * @param symmAlgParams symmetric algorithm parameters - * @param symmetricKey symmetric key data - * @param type symmetric key algorithm - * @param strength symmetric key strength in bytes - * @return Symmetric key object - * @throws Exception - */ - - public SymmetricKey unwrap_symmetric(byte sessionKey[], String symmAlgOID, - byte symmAlgParams[], byte symmetricKey[], Type type, int strength) - throws Exception; - - /** * Unwraps symmetric key . This method * unwraps the symmetric key. * * @param encSymmKey wrapped symmetric key to be unwrapped * @return Symmetric key object - */ - - public SymmetricKey unwrap_session_key(CryptoToken token, byte encSymmKey[], - SymmetricKey.Usage usage, WrappingParams params); - - public PrivateKey unwrap_temp(byte privateKey[], PublicKey pubKey) - throws Exception; - - /** - * Unwraps data. This method rebuilds the private key by - * unwrapping the private key data. - * - * @param privateKey private key data - * @param pubKey public key object - * @return private key object * @throws Exception */ - public PrivateKey unwrap(byte privateKey[], PublicKey pubKey) - throws Exception; - /** - * Encrypts the internal private key (private key to the KRA's - * internal storage). - * - * @param rawPrivate user's private key (key to be archived) - * @return encrypted data - * @exception EBaseException failed to encrypt - */ - public byte[] encryptInternalPrivate(byte rawPrivate[]) throws Exception; + public SymmetricKey unwrap_session_key(CryptoToken token, byte encSymmKey[], + SymmetricKey.Usage usage, WrappingParams params) throws Exception; - /** - * Decrypts the internal private key (private key from the KRA's - * internal storage). - * - * @param wrappedPrivateData unwrapped private key data (key to be recovered) - * @return raw private key - * @throws Exception - */ - public byte[] decryptInternalPrivate(byte wrappedPrivateData[]) - throws Exception; - /** - * Decrypts the external private key (private key from the end-user). - * - * @param sessionKey session key that protects the user private - * @param symmAlgOID symmetric algorithm - * @param symmAlgParams symmetric algorithm parameters - * @param privateKey private key data - * @return private key data - * @throws Exception - */ - public byte[] decryptExternalPrivate(byte sessionKey[], - String symmAlgOID, - byte symmAlgParams[], byte privateKey[]) - throws Exception; + public WrappingParams getWrappingParams() throws EBaseException; - /** - * Decrypts the external private key (private key from the end-user). - * - * @param sessionKey session key that protects the user private - * @param symmAlgOID symmetric algorithm - * @param symmAlgParams symmetric algorithm parameters - * @param privateKey private key data - * @param transportCert transport certificate - * @return private key data - * @throws Exception - */ - public byte[] decryptExternalPrivate(byte sessionKey[], - String symmAlgOID, byte symmAlgParams[], byte privateKey[], - org.mozilla.jss.crypto.X509Certificate transportCert) - throws Exception; + public WrappingParams getOldWrappingParams(); } diff --git a/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java b/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java index 4e651d394..6f6e31201 100644 --- a/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java +++ b/base/common/src/com/netscape/certsrv/security/IStorageKeyUnit.java @@ -17,9 +17,12 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.certsrv.security; +import java.security.PublicKey; import java.util.Enumeration; import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.PrivateKey; +import org.mozilla.jss.crypto.SymmetricKey; import com.netscape.certsrv.base.EBaseException; @@ -96,4 +99,74 @@ public interface IStorageKeyUnit extends IEncryptionUnit { public CryptoToken getToken(); + /** + * Encrypts the internal private key (private key to the KRA's + * internal storage). + * + * @param rawPrivate user's private key (key to be archived) + * @return encrypted data + * @exception EBaseException failed to encrypt + */ + public byte[] encryptInternalPrivate(byte rawPrivate[]) throws Exception; + + /** + * Wraps data. The given key will be wrapped by the + * private key in this unit. + * + * @param priKey private key to be wrapped + * @param WrappingParams - wrapping parameters + * @return wrapped data + * @exception EBaseException failed to wrap + */ + public byte[] wrap(PrivateKey priKey) throws Exception; + + /** + * Wraps data. The given key will be wrapped by the + * private key in this unit. + * + * @param symKey symmetric key to be wrapped + * @param wrappingParams - wrapping parameters + * @return wrapped data + * @exception EBaseException failed to wrap + */ + public byte[] wrap(SymmetricKey symKey) throws Exception; + + /** + * Decrypts the internal private key (private key from the KRA's + * internal storage). + * + * @param wrappedPrivateData unwrapped private key data (key to be recovered) + * @param params - wrapping params + * @return raw private key + * @throws Exception + */ + public byte[] decryptInternalPrivate(byte wrappedPrivateData[], WrappingParams params) + throws Exception; + + /** + * Unwraps symmetric key data. This method rebuilds the symmetric key by + * unwrapping the private data blob. + * + * @param wrappedKeyData symmetric key data wrapped up with session key + * @return Symmetric key object + * @exception Exception failed to unwrap + */ + + public SymmetricKey unwrap(byte wrappedKeyData[], SymmetricKey.Type algorithm, int keySize, + WrappingParams params) throws Exception; + + /** + * Unwraps data. This method rebuilds the private key by + * unwrapping the private key data. + * + * @param privateKey private key data + * @param pubKey public key object + * @param temporary - temporary key? + * @param params - wrapping parameters + * @return private key object + * @throws Exception + */ + public PrivateKey unwrap(byte privateKey[], PublicKey pubKey, boolean temporary, + WrappingParams params) throws Exception; + } diff --git a/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java b/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java index 965101ffa..c90a12ba1 100644 --- a/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java +++ b/base/common/src/com/netscape/certsrv/security/ITransportKeyUnit.java @@ -22,6 +22,7 @@ import java.security.PublicKey; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SymmetricKey; +import org.mozilla.jss.crypto.SymmetricKey.Type; import com.netscape.certsrv.base.EBaseException; @@ -63,58 +64,87 @@ public interface ITransportKeyUnit extends IEncryptionUnit { public PrivateKey getPrivateKey(org.mozilla.jss.crypto.X509Certificate cert); /** - * Unwraps symmetric key . This method - * unwraps the symmetric key. - * - * @param encSymmKey wrapped symmetric key to be unwrapped - * @param usage Key usage for unwrapped key. - * @return Symmetric key object + * Returns this Unit's crypto token object. + * @return CryptoToken object. + */ + + public CryptoToken getToken(); + + /** + * Returns this Unit's signing algorithm in String format. + * @return String of signing algorithm + * @throws EBaseException */ - public SymmetricKey unwrap_session_key(CryptoToken token, byte encSymmKey[], SymmetricKey.Usage usage, - WrappingParams params); + public String getSigningAlgorithm() throws EBaseException; + + /** + * Sets this Unit's signing algorithm. + * @param str String of signing algorithm to set. + * @throws EBaseException + */ + public void setSigningAlgorithm(String str) throws EBaseException; + + /** + * Decrypts the external private key (private key from the end-user). + * + * @param sessionKey session key that protects the user private + * @param symmAlgOID symmetric algorithm + * @param symmAlgParams symmetric algorithm parameters + * @param privateKey private key data + * @param transportCert transport certificate + * @return private key data + * @throws Exception + */ + public byte[] decryptExternalPrivate(byte sessionKey[], + String symmAlgOID, byte symmAlgParams[], byte privateKey[], + org.mozilla.jss.crypto.X509Certificate transportCert) + throws Exception; /** * Unwraps symmetric key . This method * unwraps the symmetric key. * - * @param encSymmKey wrapped symmetric key to be unwrapped + * @param sessionKey session key that unwrap the symmetric key + * @param symmAlgOID symmetric algorithm + * @param symmAlgParams symmetric algorithm parameters + * @param symmetricKey symmetric key data + * @param type symmetric key algorithm + * @param strength symmetric key strength in bytes * @return Symmetric key object + * @throws Exception */ - public SymmetricKey unwrap_sym(byte encSymmKey[], WrappingParams params); + public SymmetricKey unwrap_symmetric(byte sessionKey[], String symmAlgOID, + byte symmAlgParams[], byte symmetricKey[], Type type, int strength) + throws Exception; /** - * Unwraps temporary private key . This method - * unwraps the temporary private key. + * Unwraps data. This method rebuilds the private key by + * unwrapping the private key data. * - * @param wrappedKeyData wrapped private key to be unwrapped + * @param symmAlgOID symmetric algorithm + * @param symmAlgParams symmetric algorithm parameters * @param pubKey public key - * @return Private key object + * @param transportCert transport certificate + * @return private key object * @throws Exception */ + public PrivateKey unwrap(byte encSymmKey[], String symmAlgOID, + byte symmAlgParams[], byte encValue[], PublicKey pubKey, + org.mozilla.jss.crypto.X509Certificate transportCert) + throws Exception; - public PrivateKey unwrap_temp(byte wrappedKeyData[], PublicKey - pubKey) throws Exception; /** - * Returns this Unit's crypto token object. - * @return CryptoToken object. + * Unwraps symmetric key . This method + * unwraps the symmetric key. + * + * @param encSymmKey wrapped symmetric key to be unwrapped + * @return Symmetric key object + * @throws Exception */ - public CryptoToken getToken(); - - /** - * Returns this Unit's signing algorithm in String format. - * @return String of signing algorithm - * @throws EBaseException - */ + public SymmetricKey unwrap_sym(byte encSymmKey[], WrappingParams params) throws Exception; - public String getSigningAlgorithm() throws EBaseException; - /** - * Sets this Unit's signing algorithm. - * @param str String of signing algorithm to set. - * @throws EBaseException - */ - public void setSigningAlgorithm(String str) throws EBaseException; } diff --git a/base/common/src/com/netscape/certsrv/security/WrappingParams.java b/base/common/src/com/netscape/certsrv/security/WrappingParams.java index 9689ecc60..5d8dc3a6e 100644 --- a/base/common/src/com/netscape/certsrv/security/WrappingParams.java +++ b/base/common/src/com/netscape/certsrv/security/WrappingParams.java @@ -1,16 +1,18 @@ package com.netscape.certsrv.security; +import java.security.NoSuchAlgorithmException; + +import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; import org.mozilla.jss.crypto.EncryptionAlgorithm; +import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyWrapAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.SymmetricKey.Type; -import org.mozilla.jss.crypto.SymmetricKey.Usage; public class WrappingParams { // session key attributes - SymmetricKey.Type skTyoe; - SymmetricKey.Usage[] skUsages; + SymmetricKey.Type skType; KeyGenAlgorithm skKeyGenAlgorithm; int skLength; @@ -23,33 +25,82 @@ public class WrappingParams { //wrapping algorithm for payload KeyWrapAlgorithm payloadWrapAlgorithm; - public WrappingParams(Type skTyoe, Usage[] skUsages, KeyGenAlgorithm skKeyGenAlgorithm, int skLength, + // payload encryption IV + IVParameterSpec payloadEncryptionIV; + + // payload wrapping IV + IVParameterSpec payloadWrappingIV; + + public WrappingParams(Type skType, KeyGenAlgorithm skKeyGenAlgorithm, int skLength, KeyWrapAlgorithm skWrapAlgorithm, EncryptionAlgorithm payloadEncryptionAlgorithm, - KeyWrapAlgorithm payloadWrapAlgorithm) { + KeyWrapAlgorithm payloadWrapAlgorithm, IVParameterSpec payloadEncryptIV, IVParameterSpec payloadWrapIV) { super(); - this.skTyoe = skTyoe; - this.skUsages = skUsages; + this.skType = skType; this.skKeyGenAlgorithm = skKeyGenAlgorithm; this.skLength = skLength; this.skWrapAlgorithm = skWrapAlgorithm; this.payloadEncryptionAlgorithm = payloadEncryptionAlgorithm; this.payloadWrapAlgorithm = payloadWrapAlgorithm; + this.payloadEncryptionIV = payloadEncryptIV; + this.payloadWrappingIV = payloadWrapIV; } - public SymmetricKey.Type getSkTyoe() { - return skTyoe; + public WrappingParams() {} + + public WrappingParams(String encryptOID, String wrapName, String priKeyAlgo, IVParameterSpec encryptIV, IVParameterSpec wrapIV) + throws NumberFormatException, NoSuchAlgorithmException { + EncryptionAlgorithm encrypt = EncryptionAlgorithm.fromOID(new OBJECT_IDENTIFIER(encryptOID)); + + KeyWrapAlgorithm wrap = null; + if (wrapName != null) { + wrap = KeyWrapAlgorithm.fromString(wrapName); + this.payloadWrapAlgorithm = wrap; + } + + switch (encrypt.getAlg().toString()) { + case "AES": + this.skType = SymmetricKey.AES; + this.skKeyGenAlgorithm = KeyGenAlgorithm.AES; + if (wrap == null) this.payloadWrapAlgorithm = KeyWrapAlgorithm.AES_KEY_WRAP_PAD; + break; + case "DESede": + this.skType = SymmetricKey.DES3; + this.skKeyGenAlgorithm = KeyGenAlgorithm.DES3; + this.skWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD; + if (wrap == null) this.payloadWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD; + break; + case "DES": + this.skType = SymmetricKey.DES; + this.skKeyGenAlgorithm = KeyGenAlgorithm.DES; + this.skWrapAlgorithm = KeyWrapAlgorithm.DES3_CBC_PAD; + if (wrap == null) this.payloadWrapAlgorithm = KeyWrapAlgorithm.DES_CBC_PAD; + break; + default: + throw new NoSuchAlgorithmException("Invalid algorithm"); + } + + this.skLength = encrypt.getKeyStrength(); + if (priKeyAlgo.equals("EC")) { + this.skWrapAlgorithm = KeyWrapAlgorithm.AES_ECB; + } else { + this.skWrapAlgorithm = KeyWrapAlgorithm.RSA; + } + + this.payloadEncryptionAlgorithm = encrypt; + this.payloadEncryptionIV = encryptIV; + this.payloadWrappingIV = wrapIV; } - public void setSkTyoe(SymmetricKey.Type skTyoe) { - this.skTyoe = skTyoe; + public SymmetricKey.Type getSkType() { + return skType; } - public SymmetricKey.Usage[] getSkUsages() { - return skUsages; + public void setSkType(SymmetricKey.Type skType) { + this.skType = skType; } - public void setSkUsages(SymmetricKey.Usage[] skUsages) { - this.skUsages = skUsages; + public void setSkType(String skTypeName) throws NoSuchAlgorithmException { + this.skType = SymmetricKey.Type.fromName(skTypeName); } public KeyGenAlgorithm getSkKeyGenAlgorithm() { @@ -60,6 +111,20 @@ public class WrappingParams { this.skKeyGenAlgorithm = skKeyGenAlgorithm; } + public void setSkKeyGenAlgorithm(String algName) throws NoSuchAlgorithmException { + // JSS mapping is not working. Lets just do something brain-dead to + // handle the cases we expect. + if (algName.equalsIgnoreCase("AES")) { + this.skKeyGenAlgorithm = KeyGenAlgorithm.AES; + } else if (algName.equalsIgnoreCase("DES")) { + this.skKeyGenAlgorithm = KeyGenAlgorithm.DES; + } else if (algName.equalsIgnoreCase("DESede")) { + this.skKeyGenAlgorithm = KeyGenAlgorithm.DES3; + } else if (algName.equalsIgnoreCase("DES3")) { + this.skKeyGenAlgorithm = KeyGenAlgorithm.DES3; + } + } + public int getSkLength() { return skLength; } @@ -76,6 +141,10 @@ public class WrappingParams { this.skWrapAlgorithm = skWrapAlgorithm; } + public void setSkWrapAlgorithm(String name) throws NoSuchAlgorithmException { + this.skWrapAlgorithm = KeyWrapAlgorithm.fromString(name); + } + public EncryptionAlgorithm getPayloadEncryptionAlgorithm() { return payloadEncryptionAlgorithm; } @@ -84,6 +153,11 @@ public class WrappingParams { this.payloadEncryptionAlgorithm = payloadEncryptionAlgorithm; } + public void setPayloadEncryptionAlgorithm(String algName, String modeName, String paddingName, int keyStrength) + throws NoSuchAlgorithmException { + this.payloadEncryptionAlgorithm = EncryptionAlgorithm.lookup(algName, modeName, paddingName, keyStrength); + } + public KeyWrapAlgorithm getPayloadWrapAlgorithm() { return payloadWrapAlgorithm; } @@ -91,4 +165,24 @@ public class WrappingParams { public void setPayloadWrapAlgorithm(KeyWrapAlgorithm payloadWrapAlgorithm) { this.payloadWrapAlgorithm = payloadWrapAlgorithm; } + + public void setPayloadWrapAlgorithm(String name) throws NoSuchAlgorithmException { + this.payloadWrapAlgorithm = KeyWrapAlgorithm.fromString(name); + } + + public IVParameterSpec getPayloadEncryptionIV() { + return payloadEncryptionIV; + } + + public void setPayloadEncryptionIV(IVParameterSpec payloadEncryptionIV) { + this.payloadEncryptionIV = payloadEncryptionIV; + } + + public IVParameterSpec getPayloadWrappingIV() { + return payloadWrappingIV; + } + + public void setPayloadWrappingIV(IVParameterSpec payloadWrappingIV) { + this.payloadWrappingIV = payloadWrappingIV; + } } diff --git a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java index 7c20e5cf4..a2d204347 100644 --- a/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java +++ b/base/common/src/com/netscape/certsrv/util/NSSCryptoProvider.java @@ -1,26 +1,19 @@ package com.netscape.certsrv.util; -import java.io.CharConversionException; import java.io.File; -import java.io.IOException; import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; import org.mozilla.jss.CertDatabaseException; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.CryptoManager.NotInitializedException; import org.mozilla.jss.KeyDatabaseException; -import org.mozilla.jss.asn1.InvalidBERException; import org.mozilla.jss.crypto.AlreadyInitializedException; -import org.mozilla.jss.crypto.BadPaddingException; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; -import org.mozilla.jss.crypto.IllegalBlockSizeException; import org.mozilla.jss.crypto.KeyGenAlgorithm; +import org.mozilla.jss.crypto.KeyWrapAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.TokenException; import org.mozilla.jss.util.IncorrectPasswordException; @@ -110,7 +103,7 @@ public class NSSCryptoProvider extends CryptoProvider { if (token == null) { throw new NotInitializedException(); } - return CryptoUtil.generateKey(token, getKeyGenAlgorithm(keyAlgorithm), keySize); + return CryptoUtil.generateKey(token, getKeyGenAlgorithm(keyAlgorithm), keySize, null, false); } @Override @@ -142,7 +135,7 @@ public class NSSCryptoProvider extends CryptoProvider { if (token == null) { throw new NotInitializedException(); } - return CryptoUtil.unwrapUsingSymmetricKey(token, new IVParameterSpec(nonceData), wrappedRecoveredKey, + return CryptoUtil.decryptUsingSymmetricKey(token, new IVParameterSpec(nonceData), wrappedRecoveredKey, recoveryKey, getEncryptionAlgorithm(encryptionAlgorithm)); } @@ -211,10 +204,7 @@ public class NSSCryptoProvider extends CryptoProvider { @Override public byte[] createPKIArchiveOptions(String transportCert, SymmetricKey secret, String passphrase, - String keyAlgorithm, int symKeySize, byte[] nonceData) throws InvalidKeyException, - CertificateEncodingException, CharConversionException, NoSuchAlgorithmException, - InvalidAlgorithmParameterException, IllegalStateException, TokenException, IOException, - IllegalBlockSizeException, BadPaddingException, InvalidBERException { + String keyAlgorithm, int symKeySize, byte[] nonceData) throws Exception { return CryptoUtil.createPKIArchiveOptions(manager, token, transportCert, secret, passphrase, getKeyGenAlgorithm(keyAlgorithm), symKeySize, new IVParameterSpec(nonceData)); @@ -222,8 +212,13 @@ public class NSSCryptoProvider extends CryptoProvider { @Override public byte[] wrapWithSessionKey(SymmetricKey secret, SymmetricKey sessionKey, byte[] iv) - throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, TokenException { - return CryptoUtil.wrapSymmetricKey(token, secret, sessionKey, new IVParameterSpec(iv)); + throws Exception { + return CryptoUtil.wrapUsingSymmetricKey( + token, + sessionKey, + secret, + new IVParameterSpec(iv), + KeyWrapAlgorithm.DES3_CBC_PAD); } } diff --git a/base/common/src/org/dogtagpki/tps/TPSConnection.java b/base/common/src/org/dogtagpki/tps/TPSConnection.java index c5a971edd..dd9538b18 100644 --- a/base/common/src/org/dogtagpki/tps/TPSConnection.java +++ b/base/common/src/org/dogtagpki/tps/TPSConnection.java @@ -93,9 +93,11 @@ public class TPSConnection { String s = message.encode(); // don't print the pdu_data - int idx = s.lastIndexOf("pdu_data="); - String toDebug = null; - if (idx == -1) + int idx = s.lastIndexOf("pdu_data="); + + int debug = 0; + String toDebug = null; + if (idx == -1 || debug == 1) CMS.debug("TPSConnection.write: Writing: " + s); else { toDebug = s.substring(0, idx-1); diff --git a/base/common/src/org/dogtagpki/tps/apdu/APDU.java b/base/common/src/org/dogtagpki/tps/apdu/APDU.java index 009c47094..e3d72c764 100644 --- a/base/common/src/org/dogtagpki/tps/apdu/APDU.java +++ b/base/common/src/org/dogtagpki/tps/apdu/APDU.java @@ -219,6 +219,70 @@ public abstract class APDU { data.set(dataEncrypted); } + //Used for scp03, provide a padding buffer of the requested size, first byte set to 0x80 + public void padBuffer80(TPSBuffer buffer, int blockSize) { + int length = buffer.size(); + + int padSize = 0; + + if( buffer == null || blockSize <= 0) + return; + + int rem = length % blockSize ; + + padSize = blockSize - rem; + + TPSBuffer padding = new TPSBuffer( padSize); + padding.setAt(0, (byte) 0x80); + + buffer.add(padding); + + } + + //Assume the whole buffer is to be incremented + //Used for SCP03 encrypted apdu messages + public void incrementBuffer(TPSBuffer buffer) { + + if(buffer == null) + return; + + int len = buffer.size(); + + if (len < 1) + return; + int offset = 0; + for (short i = (short) (offset + len - 1); i >= offset; i--) { + byte cur = buffer.at(i); + if (cur != (byte) 0xFF) { + cur++; + buffer.setAt(i, cur); + break; + } else + buffer.setAt(i,(byte) 0x00); + } + + System.out.println("enc buffer: " + buffer.toHexString()); + } + + //Implement SCP03 encrypted apdu scheme. + public void secureMessageSCP03(PK11SymKey encKey, TPSBuffer encryptionCounter) throws EBaseException { + + TPSBuffer data = this.getData(); + + if (data != null && data.size() > 0) { + + padBuffer80(data, 16); + + TPSBuffer encryptedCounter = Util.encryptDataAES(encryptionCounter, encKey, null); + + TPSBuffer encryptedData = Util.encryptDataAES(data, encKey, encryptedCounter); + + data.set(encryptedData); + + } + + } + public void secureMessageSCP02(PK11SymKey encKey) throws EBaseException { if (encKey == null) { diff --git a/base/common/src/org/dogtagpki/tps/main/Util.java b/base/common/src/org/dogtagpki/tps/main/Util.java index b212478d7..1410c72a2 100644 --- a/base/common/src/org/dogtagpki/tps/main/Util.java +++ b/base/common/src/org/dogtagpki/tps/main/Util.java @@ -24,6 +24,9 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.util.Calendar; @@ -34,10 +37,14 @@ import netscape.security.x509.SubjectKeyIdentifierExtension; import netscape.security.x509.X509CertImpl; import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.crypto.BadPaddingException; import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; +import org.mozilla.jss.crypto.IllegalBlockSizeException; +import org.mozilla.jss.crypto.SymmetricKey; +import org.mozilla.jss.crypto.TokenException; import org.mozilla.jss.pkcs11.PK11SymKey; import com.netscape.certsrv.apps.CMS; @@ -47,6 +54,13 @@ import com.netscape.symkey.SessionKey; public class Util { + //SCP03 AES-CMAC related constants + private static final byte AES_CMAC_CONSTANT = (byte) 0x87; + private static final int AES_CMAC_BLOCK_SIZE = 16; + + public static final byte CARD_CRYPTO_KDF_CONSTANT_SCP03 = 0x0; + public static final byte HOST_CRYPTO_KDF_CONSTANT_SCP03 = 0x1; + public Util() { } @@ -84,11 +98,6 @@ public class Util { return Integer.toHexString(val); } - public static void main(String[] args) { - // TODO Auto-generated method stub - - } - public static String uriDecode(String encoded) throws UnsupportedEncodingException { return URLDecoder.decode(encoded, "UTF-8"); @@ -332,6 +341,196 @@ public class Util { return output; } + //Use AES-CMAC (SCP03, counter method) to calculate cryptogram, constant determines whether it is a card or host cryptogram + public static TPSBuffer compute_AES_CMAC_Cryptogram(SymmetricKey symKey, TPSBuffer context, byte kdfConstant) + throws EBaseException { + + String method = "Util compute_AES_Crypto:"; + // 11 bytes label + byte[] label = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // sanity checking + + if (symKey == null || context == null ) { + throw new EBaseException(method + " Invalid input!"); + } + + TPSBuffer data = new TPSBuffer(); + int outputBits = 8 * 8; + + //output size of cmac PRF + final int h = 128; + + int remainder = outputBits % h; + + //calculate counter size + int n = 0; + if (remainder == 0) { + n = outputBits / h; + } else { + n = outputBits / h + 1; + } + + byte b1 = (byte) ((outputBits >> 8) & 0xFF); + byte b2 = (byte) (outputBits & 0xFF); + + TPSBuffer outputBitsBinary = new TPSBuffer(2); + outputBitsBinary.setAt(0, b1); + outputBitsBinary.setAt(1, b2); + + data.addBytes(label); + data.add(kdfConstant); + data.add((byte) 0x0); + data.add(outputBitsBinary); + + TPSBuffer output = new TPSBuffer(); + TPSBuffer input = new TPSBuffer(); + + TPSBuffer kI = null; + + for (int i = 1; i <= n; i++) { + input.add(data); + input.add((byte) i); + input.add(context); + + kI = Util.computeAES_CMAC(symKey, input); + + output.add(kI); + } + + return output.substr(0,8); + } + + // Implements agorithm http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf + // Input an aes key of 128, 192, or 256 bits + + public static TPSBuffer computeAES_CMAC(SymmetricKey aesKey, TPSBuffer input) throws EBaseException { + + String method = "Util.computeAES_CMAC:"; + byte iv[] = null; + + if (aesKey == null || input == null) { + throw new EBaseException(method + " invalid input data!"); + } + + TPSBuffer data = new TPSBuffer(input); + + String alg = aesKey.getAlgorithm(); + System.out.println(" AES ALG: " + alg); + + EncryptionAlgorithm eAlg = EncryptionAlgorithm.AES_128_CBC; + int ivLength = eAlg.getIVLength(); + + if (ivLength > 0) { + iv = new byte[ivLength]; + } + + if (!("AES".equals(alg))) { + throw new EBaseException(method + " invalid in put key type , must be AES!"); + } + + byte[] k0 = new byte[AES_CMAC_BLOCK_SIZE]; + + //Encrypt the zero array + CryptoToken token = aesKey.getOwningToken(); + Cipher encryptor = null; + + try { + encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + encryptor.initEncrypt(aesKey, new IVParameterSpec(iv)); + k0 = encryptor.doFinal(k0); + + } catch (NoSuchAlgorithmException | TokenException | IllegalStateException | IllegalBlockSizeException + | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new EBaseException(e); + } + + byte[] k1 = getAES_CMAC_SubKey(k0); + byte[] k2 = getAES_CMAC_SubKey(k1); + + int numBlocks = 0; + int messageSize = data.size(); + boolean perfectBlocks = false; + + if (((messageSize % AES_CMAC_BLOCK_SIZE) == 0) && (messageSize != 0)) { + numBlocks = messageSize / AES_CMAC_BLOCK_SIZE; + perfectBlocks = true; + } + else { + numBlocks = messageSize / AES_CMAC_BLOCK_SIZE + 1; + perfectBlocks = false; + } + + int index = 0; + byte inb = 0; + if (perfectBlocks == true) + { + // If the size of the message is an integer multiple of the block block size (namely, 128 bits) (16 bytes) + // the last block shall be exclusive-OR'ed with the first subKey k1 + + for (int j = 0; j < k1.length; j++) { + index = messageSize - AES_CMAC_BLOCK_SIZE + j; + inb = data.at(index); + data.setAt(index, (byte) (inb ^ k1[j])); + } + } + else + { + // Otherwise, the last block shall be padded with 10^i + TPSBuffer padding = new TPSBuffer(AES_CMAC_BLOCK_SIZE - messageSize % AES_CMAC_BLOCK_SIZE); + padding.setAt(0, (byte) 0x80); + + data.add(padding); + //Get new data size , it's changed + messageSize = data.size(); + + // and exclusive-OR'ed with K2 + for (int j = 0; j < k2.length; j++) { + index = messageSize - AES_CMAC_BLOCK_SIZE + j; + inb = data.at(index); + data.setAt(index, (byte) (inb ^ k2[j])); + } + } + + // Initialization vector starts as zeroes but changes inside the loop's + // subsequent iterations, it becomes the last encryption output + byte[] encData = new byte[AES_CMAC_BLOCK_SIZE]; + TPSBuffer currentBlock = null; + + for (int i = 0; i < numBlocks; i++) { + try { + encryptor.initEncrypt(aesKey, new IVParameterSpec(encData)); + currentBlock = data.substr(i * AES_CMAC_BLOCK_SIZE, AES_CMAC_BLOCK_SIZE); + encData = encryptor.doFinal(currentBlock.toBytesArray()); + } catch (TokenException | IllegalStateException | IllegalBlockSizeException + | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new EBaseException(e); + } + } + + TPSBuffer aesMacData = new TPSBuffer(encData); + return aesMacData; + + } + + //Support method for AES-CMAC alg (SCP03). + private static byte[] getAES_CMAC_SubKey(byte[] input) { + + byte[] output = new byte[input.length]; + + boolean msbSet = ((input[0]&0x80) != 0); + for (int i=0; i<input.length; i++) { + output[i] = (byte) (input[i] << 1); + if (i+1 < input.length && ((input[i+1]&0x80) != 0)) { + output[i] |= 0x01; + } + } + if (msbSet) { + output[output.length-1] ^= AES_CMAC_CONSTANT; + } + return output; + } + public static TPSBuffer computeMAC(PK11SymKey symKey, TPSBuffer input, TPSBuffer icv) throws EBaseException { TPSBuffer output = null; TPSBuffer result = null; @@ -425,6 +624,43 @@ public class Util { return tbuf; } + //Encrypt data with aes. Supports 128 for now. + public static TPSBuffer encryptDataAES(TPSBuffer dataToEnc, PK11SymKey encKey,TPSBuffer iv) throws EBaseException { + + TPSBuffer encrypted = null; + if (encKey == null || dataToEnc == null) { + throw new EBaseException("Util.encryptDataAES: called with no sym key or no data!"); + } + + CryptoToken token = null; + + + try { + token = CryptoManager.getInstance().getInternalKeyStorageToken(); + Cipher cipher = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + AlgorithmParameterSpec algSpec = null; + int len = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + + byte[] ivEnc = null; + if(iv == null) { //create one + ivEnc = new byte[len]; + } else { + ivEnc = iv.toBytesArray(); + } + + algSpec = new IVParameterSpec(ivEnc); + cipher.initEncrypt(encKey, algSpec); + byte[] encryptedBytes = cipher.doFinal(dataToEnc.toBytesArray()); + encrypted = new TPSBuffer(encryptedBytes); + + } catch (Exception e) { + throw new EBaseException("Util.encryptDataAES: problem encrypting data: " + e.toString()); + } + + return encrypted; + + } + public static TPSBuffer encryptData(TPSBuffer dataToEnc, PK11SymKey encKey) throws EBaseException { TPSBuffer encrypted = null; @@ -533,4 +769,328 @@ public class Util { return timeString; } + //AES CMAC test samples + public static void main(String[] args) { + + /* Options options = new Options(); + + options.addOption("d", true, "Directory for tokendb"); + + String db_dir = null; + CryptoManager cm = null; + + // 128 bit aes test key + byte devKey[] = { (byte) 0x2b, (byte) 0x7e, (byte) 0x15, (byte) 0x16, (byte) 0x28, (byte) 0xae, (byte) 0xd2, + (byte) 0xa6, (byte) 0xab, (byte) 0xf7, (byte) 0x15, (byte) 0x88, (byte) 0x09, (byte) 0xcf, (byte) 0x4f, + (byte) 0x3c }; + + // 192 bit aes test key + byte devKey192[] = { (byte) 0x8e, (byte) 0x73, (byte) 0xb0, (byte) 0xf7, (byte) 0xda, (byte) 0x0e, (byte) 0x64, + (byte) 0x52, + (byte) 0xc8, (byte) 0x10, (byte) 0xf3, (byte) 0x2b, (byte) 0x80, (byte) 0x90, (byte) 0x79, (byte) 0xe5, + (byte) 0x62, (byte) 0xf8, (byte) 0xea, (byte) 0xd2, (byte) 0x52, (byte) 0x2c, (byte) 0x6b, (byte) 0x7b + }; + + byte devKey256[] = { (byte) 0x60, (byte) 0x3d, (byte) 0xeb, (byte) 0x10, (byte) 0x15, (byte) 0xca, (byte) 0x71, + (byte) 0xbe, + (byte) 0x2b, (byte) 0x73, (byte) 0xae, (byte) 0xf0, (byte) 0x85, (byte) 0x7d, (byte) 0x77, (byte) 0x81, + (byte) 0x1f, (byte) 0x35, (byte) 0x2c, (byte) 0x07, (byte) 0x3b, (byte) 0x61, (byte) 0x08, (byte) 0xd7, + (byte) 0x2d, + (byte) 0x98, (byte) 0x10, (byte) 0xa3, (byte) 0x09, (byte) 0x14, (byte) 0xdf, (byte) 0xf4 + + }; + + byte message[] = { (byte) 0x6b, (byte) 0xc1, (byte) 0xbe, (byte) 0xe2, (byte) 0x2e, (byte) 0x40, (byte) 0x9f, + (byte) 0x96, (byte) 0xe9, (byte) 0x3d, (byte) 0x7e, (byte) 0x11, + (byte) 0x73, (byte) 0x93, (byte) 0x17, (byte) 0x2a }; + + byte message320[] = { (byte) 0x6b, (byte) 0xc1, (byte) 0xbe, (byte) 0xe2, (byte) 0x2e, (byte) 0x40, + (byte) 0x9f, (byte) 0x96, (byte) 0xe9, + (byte) 0x3d, (byte) 0x7e, (byte) 0x11, (byte) 0x73, (byte) 0x93, (byte) 0x17, (byte) 0x2a, + (byte) 0xae, (byte) 0x2d, (byte) 0x8a, (byte) 0x57, (byte) 0x1e, (byte) 0x03, (byte) 0xac, (byte) 0x9c, + (byte) 0x9e, (byte) 0xb7, + (byte) 0x6f, (byte) 0xac, (byte) 0x45, (byte) 0xaf, (byte) 0x8e, (byte) 0x51, + (byte) 0x30, (byte) 0xc8, (byte) 0x1c, (byte) 0x46, (byte) 0xa3, (byte) 0x5c, (byte) 0xe4, (byte) 0x11 }; + + byte message512[] = { (byte) 0x6b, (byte) 0xc1, (byte) 0xbe, (byte) 0xe2, (byte) 0x2e, (byte) 0x40, + (byte) 0x9f, (byte) 0x96, (byte) 0xe9, (byte) 0x3d, + (byte) 0x7e, (byte) 0x11, (byte) 0x73, (byte) 0x93, (byte) 0x17, (byte) 0x2a, + (byte) 0xae, (byte) 0x2d, (byte) 0x8a, (byte) 0x57, (byte) 0x1e, (byte) 0x03, (byte) 0xac, (byte) 0x9c, + (byte) 0x9e, (byte) 0xb7, (byte) 0x6f, + (byte) 0xac, (byte) 0x45, (byte) 0xaf, (byte) 0x8e, (byte) 0x51, + (byte) 0x30, (byte) 0xc8, (byte) 0x1c, (byte) 0x46, (byte) 0xa3, (byte) 0x5c, (byte) 0xe4, (byte) 0x11, + (byte) 0xe5, (byte) 0xfb, (byte) 0xc1, + (byte) 0x19, (byte) 0x1a, (byte) 0x0a, (byte) 0x52, (byte) 0xef, + (byte) 0xf6, (byte) 0x9f, (byte) 0x24, (byte) 0x45, (byte) 0xdf, (byte) 0x4f, (byte) 0x9b, (byte) 0x17, + (byte) 0xad, (byte) 0x2b, (byte) 0x41, + (byte) 0x7b, (byte) 0xe6, (byte) 0x6c, (byte) 0x37, (byte) 0x10 + + }; + + + byte message_test1[] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x04,0x0,0x0,(byte) 0x80,0x01, + (byte)0xd0,(byte)0x61,(byte) 0xff,(byte)0xf4,(byte)0xd8,(byte)0x2f,(byte)0xdf, + (byte)0x87,(byte)0x5a,(byte)0x5c,(byte)0x90,(byte)0x99,(byte)0x98,(byte)0x3b,(byte)0x24,(byte)0xdc }; + + byte devKey_test1[] = {(byte)0x88,(byte)0xc6,(byte)0x46,(byte)0x2e,(byte)0x55,(byte)0x58,(byte)0x6c, + (byte)0x47,(byte)0xf9,(byte)0xff,0x00,(byte)0x92,(byte)0x39,(byte)0xce,(byte)0xb6,(byte)0xea}; + + //Test keys and messages found here: http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf + //Results computed in this test program can be compared against those in the preceding document. + + try { + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = parser.parse(options, args); + + if (cmd.hasOption("d")) { + db_dir = cmd.getOptionValue("d"); + } + + } catch (ParseException e) { + System.err.println("Error in parsing command line options: " + e.getMessage()); + + } + + SymmetricKey aes128 = null; + SymmetricKey aes192 = null; + SymmetricKey aes256 = null; + + SymmetricKey tempKey = null; + + // Initialize token + try { + CryptoManager.initialize(db_dir); + cm = CryptoManager.getInstance(); + + CryptoToken token = cm.getInternalKeyStorageToken(); + + // Generate temp key with only function is to + // unwrap the various test keys onto the token + + KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.AES); + + SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4]; + usages[0] = SymmetricKey.Usage.WRAP; + usages[1] = SymmetricKey.Usage.UNWRAP; + usages[2] = SymmetricKey.Usage.ENCRYPT; + usages[3] = SymmetricKey.Usage.DECRYPT; + + kg.setKeyUsages(usages); + kg.temporaryKeys(true); + kg.initialize(128); + tempKey = kg.generate(); + + //unwrap the test aes keys onto the token + + Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + + int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + byte[] iv = null; + + if (ivLength > 0) { + iv = new byte[ivLength]; // all zeroes + } + + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey = encryptor.doFinal(devKey); + + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[]wrappedKey_test1 = encryptor.doFinal(devKey_test1); + + // 192 bit key + + TPSBuffer aesKey192Buf = new TPSBuffer(devKey192); + TPSBuffer aesKey192Pad = new TPSBuffer(8); + aesKey192Pad.setAt(0, (byte) 0x80); + aesKey192Buf.add(aesKey192Pad); + + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey192 = encryptor.doFinal(aesKey192Buf.toBytesArray()); + + // 128 bit key + + KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap.initUnwrap(tempKey, new IVParameterSpec(iv)); + aes128 = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.AES, 16); + + + KeyWrapper keyWrap1 = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap1.initUnwrap(tempKey,new IVParameterSpec(iv)); + SymmetricKey aes128_test = keyWrap1.unwrapSymmetric(wrappedKey_test1,SymmetricKey.AES,16); + + System.out.println(new TPSBuffer(message_test1).toHexString()); + System.out.println(new TPSBuffer(devKey_test1).toHexString()); + System.out.println(new TPSBuffer(aes128_test.getKeyData()).toHexString()); + TPSBuffer input1 = new TPSBuffer(message_test1); + TPSBuffer output1 = Util.computeAES_CMAC(aes128_test, input1); + System.out.println("blub: " + output1.toHexString()); + + // 192 bit key + + KeyWrapper keyWrap192 = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap192.initUnwrap(tempKey, new IVParameterSpec(iv)); + aes192 = keyWrap.unwrapSymmetric(wrappedKey192, SymmetricKey.AES, 24); + + // 256 bit key + + TPSBuffer aesKey256Buf = new TPSBuffer(devKey256); + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey256 = encryptor.doFinal(aesKey256Buf.toBytesArray()); + + KeyWrapper keyWrap256 = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap256.initUnwrap(tempKey, new IVParameterSpec(iv)); + aes256 = keyWrap.unwrapSymmetric(wrappedKey256, SymmetricKey.AES, 32); + + System.out.println(""); + System.out.println("Now use 128 bit AES key:"); + System.out.println(""); + + //Attempt 0 bytes + + System.out.println(""); + System.out.println("Use message of 0 bytes:"); + System.out.println(""); + + TPSBuffer input0 = new TPSBuffer(0); + TPSBuffer output0 = Util.computeAES_CMAC(aes128, input0); + + System.out.println("Message:" + input0.toHexString()); + System.out.println("AES-CMAC output: " + output0.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 16 bytes:"); + System.out.println(""); + + //Attempt 16 bytes + + TPSBuffer input = new TPSBuffer(message); + TPSBuffer output = Util.computeAES_CMAC(aes128, input); + + System.out.println("Message:" + input.toHexString()); + System.out.println("AES-CMAC output: " + output.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 40 bytes:"); + System.out.println(""); + + //Attempt 40 bytes + + TPSBuffer input320 = new TPSBuffer(message320); + TPSBuffer output320 = Util.computeAES_CMAC(aes128, input320); + + System.out.println("Message:" + input320.toHexString()); + System.out.println("AES-CMAC output: " + output320.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 64 bytes:"); + System.out.println(""); + + //Attempt 64 bytes + + TPSBuffer input512 = new TPSBuffer(message512); + TPSBuffer output512 = Util.computeAES_CMAC(aes128, input512); + System.out.println("Message:" + input512.toHexString()); + System.out.println("AES-CMAC output: " + output512.toHexString()); + + // Now used the AES 192 key + + System.out.println(""); + System.out.println("Now use 192 bit AES key:"); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 0 bytes:"); + System.out.println(""); + + // Attempt 0 bytes + + TPSBuffer input192_0 = new TPSBuffer(0); + TPSBuffer output192_0 = Util.computeAES_CMAC(aes192, input192_0); + System.out.println("Message:" + input192_0.toHexString()); + System.out.println("AES-CMAC output: " + output192_0.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 16 bytes:"); + System.out.println(""); + + //Attempt 16 bytes + + TPSBuffer input192_128 = new TPSBuffer(message); + TPSBuffer output192_128 = Util.computeAES_CMAC(aes192, input); + System.out.println("Message:" + input192_128.toHexString()); + System.out.println("AES-CMAC output: " + output192_128.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 40 bytes:"); + System.out.println(""); + + //Attempt 40 bytes + + TPSBuffer input192_320 = new TPSBuffer(message320); + TPSBuffer output192_320 = Util.computeAES_CMAC(aes192, input192_320); + System.out.println("Message:" + input192_320.toHexString()); + System.out.println("AES-CMAC output: " + output192_320.toHexString()); + System.out.println(""); + + System.out.println(""); + System.out.println("Use message of 64 bytes:"); + System.out.println(""); + + //Attempt 64 bytes + + TPSBuffer input192_512 = new TPSBuffer(message512); + TPSBuffer output192_512 = Util.computeAES_CMAC(aes192, input512); + System.out.println("Message:" + input192_512.toHexString()); + System.out.println("AES-CMAC output: " + output192_512.toHexString()); + + System.out.println(""); + System.out.println("Now use 256 bit AES key:"); + System.out.println(""); + + // Attempt 0 bytes + + TPSBuffer input256_0 = new TPSBuffer(0); + TPSBuffer output256_0 = Util.computeAES_CMAC(aes256, input256_0); + System.out.println("Message:" + input256_0.toHexString()); + System.out.println("AES-CMAC output: " + output256_0.toHexString()); + System.out.println(""); + + //Attempt 16 bytes + + TPSBuffer input256_128 = new TPSBuffer(message); + TPSBuffer output256_128 = Util.computeAES_CMAC(aes256, input256_128); + System.out.println("Message:" + input256_128.toHexString()); + System.out.println("AES-CMAC output: " + output256_128.toHexString()); + System.out.println(""); + + //Attempt 40 bytes + + TPSBuffer input256_320 = new TPSBuffer(message320); + TPSBuffer output256_320 = Util.computeAES_CMAC(aes256, input256_320); + System.out.println("Message:" + input256_320.toHexString()); + System.out.println("AES-CMAC output: " + output256_320.toHexString()); + System.out.println(""); + + //Attempt 64 bytes + + TPSBuffer input256_512 = new TPSBuffer(message512); + TPSBuffer output256_512 = Util.computeAES_CMAC(aes256, input256_512); + System.out.println("Message:" + input256_512.toHexString()); + System.out.println("AES-CMAC output: " + output256_512.toHexString()); + + } catch (AlreadyInitializedException e) { + // it is ok if it is already initialized + } catch (Exception e) { + System.err.println("JSS error!" + e); + System.exit(1); + } +*/ + } + + } diff --git a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java index c7ad7f7c3..aee430247 100644 --- a/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java +++ b/base/common/src/org/dogtagpki/tps/msg/TPSMessage.java @@ -527,6 +527,12 @@ public class TPSMessage { } } + int debug = 1; + + if (debug == 1) { + CMS.debug("TPSMessage.createMessage: message: " + message); + } + TPSMessage new_msg = new TPSMessage(message); return new_msg.createMessage(); diff --git a/base/java-tools/bin/pki b/base/java-tools/bin/pki index 53e1b893a..6060a6e11 100644 --- a/base/java-tools/bin/pki +++ b/base/java-tools/bin/pki @@ -1,7 +1,6 @@ -#!/usr/bin/python -# Authors: -# Endi S. Dewata <edewata@redhat.com> +#!/bin/sh # +# --- BEGIN COPYRIGHT BLOCK --- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. @@ -15,222 +14,26 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -# Copyright (C) 2014 Red Hat, Inc. +# Copyright (C) 2017 Red Hat, Inc. # All rights reserved. +# --- END COPYRIGHT BLOCK --- # -from __future__ import absolute_import -from __future__ import print_function -import shlex -import subprocess -import sys -import traceback +# default PKI configuration +. /usr/share/pki/etc/pki.conf -import pki.cli -import pki.cli.pkcs12 +# system-wide PKI configuration +if [ -f /etc/pki/pki.conf ] +then + . /etc/pki/pki.conf +fi +# user-specific PKI configuration +if [ -f $HOME/.dogtag/pki.conf ] +then + . $HOME/.dogtag/pki.conf +fi -PYTHON_COMMANDS = ['pkcs12-import'] +python -m pki.cli.main "$@" - -class PKICLI(pki.cli.CLI): - - def __init__(self): - super(PKICLI, self).__init__( - 'pki', 'PKI command-line interface') - - self.database = None - self.password = None - self.password_file = None - self.token = None - - self.add_module(pki.cli.pkcs12.PKCS12CLI()) - - def get_full_module_name(self, module_name): - return module_name - - def print_help(self): - print('Usage: pki [OPTIONS]') - print() - print(' --client-type <type> PKI client type (default: java)') - print(' -d <path> Client security database location ' + - '(default: ~/.dogtag/nssdb)') - print(' -c <password> Client security database password ' + - '(mutually exclusive to the -C option)') - print(' -C <path> Client-side password file ' + - '(mutually exclusive to the -c option)') - print(' --token <name> Security token name') - print() - print(' -v, --verbose Run in verbose mode.') - print(' --debug Show debug messages.') - print(' --help Show help message.') - print() - - super(PKICLI, self).print_help() - - def execute_java(self, args, stdout=sys.stdout): - - # read Java home - value = subprocess.check_output( - '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $JAVA_HOME', - shell=True) - java_home = value.decode(sys.getfilesystemencoding()).strip() - - # read PKI library - value = subprocess.check_output( - '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_LIB', - shell=True) - pki_lib = value.decode(sys.getfilesystemencoding()).strip() - - # read logging configuration path - value = subprocess.check_output( - '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $LOGGING_CONFIG', - shell=True) - logging_config = value.decode(sys.getfilesystemencoding()).strip() - - cmd = [ - java_home + '/bin/java', - '-Djava.ext.dirs=' + pki_lib, - '-Djava.util.logging.config.file=' + logging_config, - 'com.netscape.cmstools.cli.MainCLI' - ] - - # restore options for Java commands - - if self.database: - cmd.extend(['-d', self.database]) - - if self.password: - cmd.extend(['-c', self.password]) - - if self.password_file: - cmd.extend(['-C', self.password_file]) - - if self.token and self.token != 'internal': - cmd.extend(['--token', self.token]) - - if self.verbose: - cmd.extend(['--verbose']) - - cmd.extend(args) - - if self.verbose: - print('Java command: %s' % ' '.join(cmd)) - - subprocess.check_call(cmd, stdout=stdout) - - def execute(self, argv): - - # append global options - value = subprocess.check_output( - '. /usr/share/pki/etc/pki.conf && . /etc/pki/pki.conf && echo $PKI_CLI_OPTIONS', - shell=True) - value = value.decode(sys.getfilesystemencoding()).strip() - args = shlex.split(value) - args.extend(argv[1:]) - - client_type = 'java' - - pki_options = [] - command = None - cmd_args = [] - - # read pki options before the command - # remove options for Python module - - i = 0 - while i < len(args): - # if arg is a command, stop - if args[i][0] != '-': - command = args[i] - break - - # get database path - if args[i] == '-d': - self.database = args[i + 1] - pki_options.append(args[i]) - pki_options.append(args[i + 1]) - i = i + 2 - - # get database password - elif args[i] == '-c': - self.password = args[i + 1] - pki_options.append(args[i]) - pki_options.append(args[i + 1]) - i = i + 2 - - # get database password file path - elif args[i] == '-C': - self.password_file = args[i + 1] - pki_options.append(args[i]) - pki_options.append(args[i + 1]) - i = i + 2 - - # get token name - elif args[i] == '--token': - self.token = args[i + 1] - pki_options.append(args[i]) - pki_options.append(args[i + 1]) - i = i + 2 - - # check verbose option - elif args[i] == '-v' or args[i] == '--verbose': - self.set_verbose(True) - pki_options.append(args[i]) - i = i + 1 - - # check debug option - elif args[i] == '--debug': - self.set_verbose(True) - self.set_debug(True) - pki_options.append(args[i]) - i = i + 1 - - # get client type - elif args[i] == '--client-type': - client_type = args[i + 1] - pki_options.append(args[i]) - pki_options.append(args[i + 1]) - i = i + 2 - - else: # otherwise, save the arg for the next module - cmd_args.append(args[i]) - i = i + 1 - - # save the rest of the args - while i < len(args): - cmd_args.append(args[i]) - i = i + 1 - - if self.verbose: - print('PKI options: %s' % ' '.join(pki_options)) - print('PKI command: %s %s' % (command, ' '.join(cmd_args))) - - if client_type == 'python' or command in PYTHON_COMMANDS: - (module, module_args) = self.parse_args(cmd_args) - module.execute(module_args) - - elif client_type == 'java': - self.execute_java(cmd_args) - - else: - raise Exception('Unsupported client type: ' + client_type) - - -if __name__ == '__main__': - - cli = PKICLI() - - try: - cli.execute(sys.argv) - - except subprocess.CalledProcessError as e: - if cli.verbose: - print('ERROR: %s' % e) - elif cli.debug: - traceback.print_exc() - sys.exit(e.returncode) - - except KeyboardInterrupt: - print() - sys.exit(-1) +exit $? diff --git a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java index 8d5bd1f8a..0a05a395a 100644 --- a/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java +++ b/base/java-tools/src/com/netscape/cmstools/CRMFPopClient.java @@ -59,7 +59,6 @@ import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.KeyPairAlgorithm; import org.mozilla.jss.crypto.KeyPairGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.Signature; import org.mozilla.jss.crypto.SignatureAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; @@ -551,9 +550,12 @@ public class CRMFPopClient { public byte[] wrapPrivateKey(CryptoToken token, SymmetricKey sessionKey, byte[] iv, KeyPair keyPair) throws Exception { // wrap private key using session - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initWrap(sessionKey, new IVParameterSpec(iv)); - return wrapper.wrap((org.mozilla.jss.crypto.PrivateKey) keyPair.getPrivate()); + return CryptoUtil.wrapUsingSymmetricKey( + token, + sessionKey, + (org.mozilla.jss.crypto.PrivateKey) keyPair.getPrivate(), + new IVParameterSpec(iv), + KeyWrapAlgorithm.DES3_CBC_PAD); } public byte[] wrapSessionKey(CryptoToken token, X509Certificate transportCert, SymmetricKey sessionKey) throws Exception { @@ -561,9 +563,7 @@ public class CRMFPopClient { // wrap session key using KRA transport cert // currently, a transport cert has to be an RSA cert, // regardless of the key you are wrapping - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA); - wrapper.initWrap(transportCert.getPublicKey(), null); - return wrapper.wrap(sessionKey); + return CryptoUtil.wrapUsingPublicKey(token, transportCert.getPublicKey(), sessionKey, KeyWrapAlgorithm.RSA); } public CertRequest createCertRequest( diff --git a/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java b/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java index 22bddcf32..a3f1deb36 100644 --- a/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java +++ b/base/java-tools/src/com/netscape/cmstools/client/ClientCertValidateCLI.java @@ -18,6 +18,7 @@ package com.netscape.cmstools.client; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -97,11 +98,13 @@ public class ClientCertValidateCLI extends CLI { CryptoManager cm = CryptoManager.getInstance(); if (cu.getUsage() != CryptoManager.CertificateUsage.CheckAllUsages.getUsage()) { - if (cm.isCertValid(nickname, true, cu)) { + try { + cm.verifyCertificate(nickname, true, cu); System.out.println("Valid certificate: " + nickname); return true; - } else { - System.out.println("Invalid certificate: " + nickname); + } catch (CertificateException e) { + // Invalid certificate: (<code>) <message> + System.out.println(e.getMessage()); return false; } diff --git a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java index 03a0729e7..6c835b439 100644 --- a/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java +++ b/base/kra/functional/src/com/netscape/cms/servlet/test/GeneratePKIArchiveOptions.java @@ -3,7 +3,6 @@ package com.netscape.cms.servlet.test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; -import java.io.CharConversionException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -11,10 +10,6 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; @@ -23,16 +18,11 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.mozilla.jss.CryptoManager; -import org.mozilla.jss.asn1.InvalidBERException; import org.mozilla.jss.crypto.AlreadyInitializedException; -import org.mozilla.jss.crypto.BadPaddingException; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.IVParameterSpec; -import org.mozilla.jss.crypto.IllegalBlockSizeException; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.SymmetricKey; -import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException; -import org.mozilla.jss.crypto.TokenException; import org.mozilla.jss.util.Password; import com.netscape.cmsutil.crypto.CryptoUtil; @@ -101,10 +91,7 @@ public class GeneratePKIArchiveOptions { out.close(); } - public static void main(String args[]) throws InvalidKeyException, CertificateEncodingException, - CharConversionException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, - IllegalStateException, TokenException, IOException, IllegalBlockSizeException, BadPaddingException, - InvalidBERException, NotExtractableException { + public static void main(String args[]) throws Exception { String token_pwd = null; String db_dir = "./"; String out_file = "./options.out"; @@ -199,7 +186,7 @@ public class GeneratePKIArchiveOptions { // Data to be archived SymmetricKey vek = null; if (!passphraseMode) { - vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0); + vek = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, false); // store vek in file write_file(Utils.base64encode(vek.getKeyData()), key_file); } diff --git a/base/kra/src/com/netscape/kra/AsymKeyGenService.java b/base/kra/src/com/netscape/kra/AsymKeyGenService.java index 7b43548d5..ffd8b03cf 100644 --- a/base/kra/src/com/netscape/kra/AsymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/AsymKeyGenService.java @@ -197,6 +197,14 @@ public class AsymKeyGenService implements IService { record.set(KeyRecord.ATTR_REALM, realm); } + try { + record.setWrappingParams(storageUnit.getOldWrappingParams()); + } catch (Exception e) { + auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(), + clientKeyId, null, "Failed to store wrapping params"); + throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE")); + } + storage.addKeyRecord(record); auditAsymKeyGenRequestProcessed(auditSubjectID, ILogger.SUCCESS, request.getRequestId(), diff --git a/base/kra/src/com/netscape/kra/EncryptionUnit.java b/base/kra/src/com/netscape/kra/EncryptionUnit.java index af4c3ec19..6d101089d 100644 --- a/base/kra/src/com/netscape/kra/EncryptionUnit.java +++ b/base/kra/src/com/netscape/kra/EncryptionUnit.java @@ -19,25 +19,19 @@ package com.netscape.kra; import java.security.PublicKey; -import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SymmetricKey; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; -import com.netscape.certsrv.key.KeyRequestResource; import com.netscape.certsrv.security.IEncryptionUnit; import com.netscape.certsrv.security.WrappingParams; - -import netscape.security.util.DerInputStream; -import netscape.security.util.DerOutputStream; -import netscape.security.util.DerValue; +import com.netscape.cmsutil.crypto.CryptoUtil; /** * A class represents the transport key pair. This key pair @@ -51,13 +45,13 @@ public abstract class EncryptionUnit implements IEncryptionUnit { /* Establish one constant IV for base class, to be used for internal operations. Constant IV acceptable for symmetric keys. */ - private byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - protected IVParameterSpec IV = null; + public static final byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + public static final byte[] iv2 = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + public static final IVParameterSpec IV = new IVParameterSpec(iv); + public static final IVParameterSpec IV2 = new IVParameterSpec(iv2); public EncryptionUnit() { CMS.debug("EncryptionUnit.EncryptionUnit this: " + this.toString()); - - IV = new IVParameterSpec(iv); } public abstract CryptoToken getToken(); @@ -72,343 +66,29 @@ public abstract class EncryptionUnit implements IEncryptionUnit { public abstract PrivateKey getPrivateKey(org.mozilla.jss.crypto.X509Certificate cert); - /** - * Protects the private key so that it can be stored in - * internal database. - */ - public byte[] encryptInternalPrivate(byte priKey[]) throws Exception { - try (DerOutputStream out = new DerOutputStream()) { - CMS.debug("EncryptionUnit.encryptInternalPrivate"); - CryptoToken internalToken = getInternalToken(); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - // (1) generate session key - SymmetricKey sk = generate_session_key(internalToken, false, params); - - // (2) wrap private key with session key - byte[] pri = encrypt_private_key(internalToken, sk, priKey, params); - - // (3) wrap session with transport public - byte[] session = wrap_session_key(internalToken, getPublicKey(), sk, params); - - // use MY own structure for now: - // SEQUENCE { - // encryptedSession OCTET STRING, - // encryptedPrivate OCTET STRING - // } + public abstract WrappingParams getWrappingParams() throws EBaseException; - DerOutputStream tmp = new DerOutputStream(); - - tmp.putOctetString(session); - tmp.putOctetString(pri); - out.write(DerValue.tag_Sequence, tmp); - - return out.toByteArray(); - } - } - - public byte[] wrap(PrivateKey privKey) throws Exception { - return _wrap(privKey,null); - } - - public byte[] wrap(SymmetricKey symmKey) throws Exception { - return _wrap(null,symmKey); + public WrappingParams getOldWrappingParams() { + return new WrappingParams( + SymmetricKey.DES3, KeyGenAlgorithm.DES3, 0, + KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, + KeyWrapAlgorithm.DES3_CBC_PAD, IV, IV); } public SymmetricKey unwrap_session_key(CryptoToken token, byte encSymmKey[], SymmetricKey.Usage usage, - WrappingParams params) { + WrappingParams params) throws Exception { PrivateKey wrappingKey = getPrivateKey(); String priKeyAlgo = wrappingKey.getAlgorithm(); if (priKeyAlgo.equals("EC")) params.setSkWrapAlgorithm(KeyWrapAlgorithm.AES_ECB); - return unwrap_session_key(token, encSymmKey, usage, wrappingKey, params); - } - - public SymmetricKey unwrap_sym(byte encSymmKey[], WrappingParams params) { - return unwrap_session_key(getToken(), encSymmKey, SymmetricKey.Usage.WRAP, params); - } - - /** - * Decrypts the user private key. - */ - public byte[] decryptExternalPrivate(byte encSymmKey[], - String symmAlgOID, byte symmAlgParams[], byte encValue[]) - throws Exception { - return decryptExternalPrivate(encSymmKey, symmAlgOID, symmAlgParams, - encValue, null); - } - - /** - * Decrypts the user private key. - */ - public byte[] decryptExternalPrivate(byte encSymmKey[], - String symmAlgOID, byte symmAlgParams[], byte encValue[], - org.mozilla.jss.crypto.X509Certificate transCert) - throws Exception { - - CMS.debug("EncryptionUnit.decryptExternalPrivate"); - CryptoToken token = getToken(transCert); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - PrivateKey wrappingKey = getPrivateKey(transCert); - String priKeyAlgo = wrappingKey.getAlgorithm(); - if (priKeyAlgo.equals("EC")) - params.setSkWrapAlgorithm(KeyWrapAlgorithm.AES_ECB); - - SymmetricKey sk = unwrap_session_key( + return CryptoUtil.unwrap( token, + params.getSkType(), + 0, + usage, wrappingKey, encSymmKey, - SymmetricKey.Usage.DECRYPT, - wrappingKey, - params); - - return decrypt_private_key(token, new IVParameterSpec(symmAlgParams), sk, encValue, params); - } - - /** - * External unwrapping. Unwraps the symmetric key using - * the transport private key. - */ - public SymmetricKey unwrap_symmetric(byte encSymmKey[], - String symmAlgOID, byte symmAlgParams[], - byte encValue[], SymmetricKey.Type algorithm, int strength) - throws Exception { - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - CryptoToken token = getToken(); - // (1) unwrap the session key - SymmetricKey sk = unwrap_session_key(token, encSymmKey, SymmetricKey.Usage.UNWRAP, params); - - // (2) unwrap the session-wrapped-symmetric-key - SymmetricKey symKey = unwrap_symmetric_key( - token, - new IVParameterSpec(symmAlgParams), - algorithm, - strength, - SymmetricKey.Usage.DECRYPT, - sk, - encValue, - params); - - return symKey; - } - - /** - * External unwrapping. Unwraps the data using - * the transport private key. - */ - public PrivateKey unwrap(byte encSymmKey[], - String symmAlgOID, byte symmAlgParams[], - byte encValue[], PublicKey pubKey) - throws Exception { - return unwrap (encSymmKey, symmAlgOID, symmAlgParams, - encValue, pubKey, null); - } - - /** - * External unwrapping. Unwraps the data using - * the transport private key. - */ - public PrivateKey unwrap(byte encSymmKey[], - String symmAlgOID, byte symmAlgParams[], - byte encValue[], PublicKey pubKey, - org.mozilla.jss.crypto.X509Certificate transCert) - throws Exception { - CryptoToken token = getToken(transCert); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - PrivateKey wrappingKey = getPrivateKey(transCert); - String priKeyAlgo = wrappingKey.getAlgorithm(); - if (priKeyAlgo.equals("EC")) - params.setSkWrapAlgorithm(KeyWrapAlgorithm.AES_ECB); - - // (1) unwrap the session key - SymmetricKey sk = unwrap_session_key( - token, - encSymmKey, - SymmetricKey.Usage.UNWRAP, - wrappingKey, - params); - - // (2) unwrap the session-wrapped-private key - return unwrap_private_key( - token, - pubKey, - new IVParameterSpec(symmAlgParams), - true /*temporary*/, - sk, - encValue, - params); - } - - /** - * External unwrapping. Unwraps the data using - * the transport private key. - */ - - public byte[] decryptInternalPrivate(byte wrappedKeyData[]) - throws Exception { - CMS.debug("EncryptionUnit.decryptInternalPrivate"); - DerValue val = new DerValue(wrappedKeyData); - // val.tag == DerValue.tag_Sequence - DerInputStream in = val.data; - DerValue dSession = in.getDerValue(); - byte session[] = dSession.getOctetString(); - DerValue dPri = in.getDerValue(); - byte pri[] = dPri.getOctetString(); - - CryptoToken token = getToken(); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - // (1) unwrap the session key - CMS.debug("decryptInternalPrivate(): getting key wrapper on slot:" + token.getName()); - SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.DECRYPT, params); - - // (2) decrypt the private key - return decrypt_private_key(token, IV, sk, pri, params); - } - - /** - * External unwrapping of stored symmetric key. - */ - public SymmetricKey unwrap(byte wrappedKeyData[], SymmetricKey.Type algorithm, int keySize) - throws Exception { - DerValue val = new DerValue(wrappedKeyData); - // val.tag == DerValue.tag_Sequence - DerInputStream in = val.data; - DerValue dSession = in.getDerValue(); - byte session[] = dSession.getOctetString(); - DerValue dPri = in.getDerValue(); - byte pri[] = dPri.getOctetString(); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - CryptoToken token = getToken(); - // (1) unwrap the session key - SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.UNWRAP, params); - - // (2) unwrap the session-wrapped-symmetric key - return unwrap_symmetric_key(token, IV, algorithm, keySize, SymmetricKey.Usage.UNWRAP, sk, pri, params); - } - - /** - * Internal unwrapping. - */ - public PrivateKey unwrap_temp(byte wrappedKeyData[], PublicKey pubKey) - throws Exception { - return _unwrap(wrappedKeyData, pubKey, true); - } - - /** - * Internal unwrapping. - */ - public PrivateKey unwrap(byte wrappedKeyData[], PublicKey pubKey) - throws Exception { - return _unwrap(wrappedKeyData, pubKey, false); - } - - /** - * Internal unwrapping. - */ - private PrivateKey _unwrap(byte wrappedKeyData[], PublicKey pubKey, boolean temporary) - throws Exception { - DerValue val = new DerValue(wrappedKeyData); - // val.tag == DerValue.tag_Sequence - DerInputStream in = val.data; - DerValue dSession = in.getDerValue(); - byte session[] = dSession.getOctetString(); - DerValue dPri = in.getDerValue(); - byte pri[] = dPri.getOctetString(); - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - CryptoToken token = getToken(); - // (1) unwrap the session key - SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.UNWRAP, params); - - // (2) unwrap the private key - return unwrap_private_key(token, pubKey, IV, temporary, sk, pri, params); - } - - /*** - * Internal wrap, accounts for either private or symmetric key - */ - private byte[] _wrap(PrivateKey priKey, SymmetricKey symmKey) throws Exception { - try (DerOutputStream out = new DerOutputStream()) { - if ((priKey == null && symmKey == null) || (priKey != null && symmKey != null)) { - return null; - } - CMS.debug("EncryptionUnit.wrap interal."); - CryptoToken token = getToken(); - - SymmetricKey.Usage usages[] = new SymmetricKey.Usage[2]; - usages[0] = SymmetricKey.Usage.WRAP; - usages[1] = SymmetricKey.Usage.UNWRAP; - - WrappingParams params = new WrappingParams( - SymmetricKey.DES3, usages, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - // (1) generate session key - SymmetricKey sk = generate_session_key(token, true, params); - - // (2) wrap private key with session key - // KeyWrapper wrapper = internalToken.getKeyWrapper( - - byte pri[] = null; - - if (priKey != null) { - pri = wrap_private_key(token, sk, priKey, params); - } else if (symmKey != null) { - pri = wrap_symmetric_key(token, sk, symmKey, params); - } - - CMS.debug("EncryptionUnit:wrap() privKey wrapped"); - - byte[] session = wrap_session_key(token, getPublicKey(), sk, params); - CMS.debug("EncryptionUnit:wrap() session key wrapped"); - - // use MY own structure for now: - // SEQUENCE { - // encryptedSession OCTET STRING, - // encryptedPrivate OCTET STRING - // } - - DerOutputStream tmp = new DerOutputStream(); - - tmp.putOctetString(session); - tmp.putOctetString(pri); - out.write(DerValue.tag_Sequence, tmp); - - return out.toByteArray(); - } + params.getSkWrapAlgorithm()); } /** @@ -418,117 +98,4 @@ public abstract class EncryptionUnit implements IEncryptionUnit { EBaseException { } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Crypto specific methods below here ... - ////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - private SymmetricKey generate_session_key(CryptoToken token, boolean temporary, WrappingParams params) - throws Exception{ - org.mozilla.jss.crypto.KeyGenerator kg = token.getKeyGenerator(params.getSkKeyGenAlgorithm()); - SymmetricKey.Usage[] usages = params.getSkUsages(); - if (usages != null) - kg.setKeyUsages(usages); - kg.temporaryKeys(temporary); - if (params.getSkLength() > 0) - kg.initialize(params.getSkLength()); - SymmetricKey sk = kg.generate(); - CMS.debug("EncryptionUnit:generate_session_key() session key generated on slot: " + token.getName()); - return sk; - } - - private byte[] wrap_session_key(CryptoToken token, PublicKey wrappingKey, SymmetricKey sessionKey, - WrappingParams params) throws Exception { - KeyWrapper rsaWrap = token.getKeyWrapper(params.getSkWrapAlgorithm()); - rsaWrap.initWrap(wrappingKey, null); - byte session[] = rsaWrap.wrap(sessionKey); - return session; - } - - public SymmetricKey unwrap_session_key(CryptoToken token, byte[] wrappedSessionKey, SymmetricKey.Usage usage, - PrivateKey wrappingKey, WrappingParams params) { - try { - KeyWrapper keyWrapper = token.getKeyWrapper(params.getSkWrapAlgorithm()); - keyWrapper.initUnwrap(wrappingKey, null); - - SymmetricKey sk = keyWrapper.unwrapSymmetric( - wrappedSessionKey, - params.getSkTyoe(), - usage, - 0); - CMS.debug("EncryptionUnit::unwrap_sym() unwrapped on slot: " - + token.getName()); - return sk; - } catch (Exception e) { - CMS.debug("EncryptionUnit::unwrap_session_key() error:" + e.toString()); - return null; - } - } - - private byte[] wrap_symmetric_key(CryptoToken token, SymmetricKey sessionKey, SymmetricKey data, - WrappingParams params) throws Exception { - KeyWrapper wrapper = token.getKeyWrapper(params.getPayloadWrapAlgorithm()); - - wrapper.initWrap(sessionKey, IV); - return wrapper.wrap(data); - } - - private SymmetricKey unwrap_symmetric_key(CryptoToken token, IVParameterSpec iv, SymmetricKey.Type algorithm, - int strength, SymmetricKey.Usage usage, SymmetricKey sessionKey, byte[] wrappedData, - WrappingParams params) throws Exception { - KeyWrapper wrapper = token.getKeyWrapper(params.getPayloadWrapAlgorithm()); - wrapper.initUnwrap(sessionKey, iv); - SymmetricKey symKey = wrapper.unwrapSymmetric(wrappedData, algorithm, usage, strength); - return symKey; - } - - private byte[] wrap_private_key(CryptoToken token, SymmetricKey sessionKey, PrivateKey data, - WrappingParams params) throws Exception { - KeyWrapper wrapper = token.getKeyWrapper(params.getPayloadWrapAlgorithm()); - wrapper.initWrap(sessionKey, IV); - return wrapper.wrap(data); - } - - private PrivateKey unwrap_private_key(CryptoToken token, PublicKey pubKey, IVParameterSpec iv, - boolean temporary, SymmetricKey sessionKey, byte[] wrappedData, WrappingParams params) - throws Exception { - KeyWrapper wrapper = token.getKeyWrapper(params.getPayloadWrapAlgorithm()); - wrapper.initUnwrap(sessionKey, iv); - - // Get the key type for unwrapping the private key. - PrivateKey.Type keyType = null; - if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.RSA_ALGORITHM)) { - keyType = PrivateKey.RSA; - } else if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.DSA_ALGORITHM)) { - keyType = PrivateKey.DSA; - } else if (pubKey.getAlgorithm().equalsIgnoreCase(KeyRequestResource.EC_ALGORITHM)) { - keyType = PrivateKey.EC; - } - - PrivateKey pk = null; - if (temporary) { - pk = wrapper.unwrapTemporaryPrivate(wrappedData, - keyType, pubKey); - } else { - pk = wrapper.unwrapPrivate(wrappedData, - keyType, pubKey); - } - return pk; - } - - private byte[] encrypt_private_key(CryptoToken token, SymmetricKey sessionKey, byte[] data, WrappingParams params) - throws Exception { - Cipher cipher = token.getCipherContext(params.getPayloadEncryptionAlgorithm()); - - cipher.initEncrypt(sessionKey, IV); - byte pri[] = cipher.doFinal(data); - return pri; - } - - private byte[] decrypt_private_key(CryptoToken token, IVParameterSpec iv, SymmetricKey sessionKey, - byte[] encryptedData, WrappingParams params) throws Exception { - Cipher cipher = token.getCipherContext(params.getPayloadEncryptionAlgorithm()); - cipher.initDecrypt(sessionKey, iv); - return cipher.doFinal(encryptedData); - } - } diff --git a/base/kra/src/com/netscape/kra/EnrollmentService.java b/base/kra/src/com/netscape/kra/EnrollmentService.java index fbefc549e..5aa35da57 100644 --- a/base/kra/src/com/netscape/kra/EnrollmentService.java +++ b/base/kra/src/com/netscape/kra/EnrollmentService.java @@ -169,7 +169,7 @@ public class EnrollmentService implements IService { if (CMS.debugOn()) CMS.debug("EnrollmentServlet: KRA services enrollment request"); - // the request reocrd field delayLDAPCommit == "true" will cause + // the request record field delayLDAPCommit == "true" will cause // updateRequest() to delay actual write to ldap request.setExtData("delayLDAPCommit", "true"); @@ -502,6 +502,22 @@ public class EnrollmentService implements IService { rec.set(KeyRecord.ATTR_REALM, realm); } + try { + rec.setWrappingParams(mStorageUnit.getWrappingParams()); + } catch (Exception e) { + mKRA.log(ILogger.LL_FAILURE, "Failed to store wrapping parameters"); + // TODO(alee) Set correct audit message here + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + throw new EKRAException(CMS.getUserMessage("CMS_KRA_INVALID_STATE")); + } + IKeyRepository storage = mKRA.getKeyRepository(); BigInteger serialNo = storage.getNextSerialNumber(); diff --git a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java index d3937915b..4dec837a0 100644 --- a/base/kra/src/com/netscape/kra/NetkeyKeygenService.java +++ b/base/kra/src/com/netscape/kra/NetkeyKeygenService.java @@ -31,7 +31,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import org.mozilla.jss.asn1.ASN1Util; -import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; @@ -39,7 +38,6 @@ import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyPairAlgorithm; import org.mozilla.jss.crypto.KeyPairGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.PQGParamGenException; import org.mozilla.jss.crypto.PQGParams; import org.mozilla.jss.crypto.PrivateKey; @@ -326,23 +324,6 @@ public class NetkeyKeygenService implements IService { } } - // this encrypts bytes with a symmetric key - public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token, - IVParameterSpec IV) { - try { - Cipher cipher = token.getCipherContext( - EncryptionAlgorithm.DES3_CBC_PAD); - - cipher.initEncrypt(symKey, IV); - byte pri[] = cipher.doFinal(toBeEncrypted); - return pri; - } catch (Exception e) { - CMS.debug("NetkeyKeygenService:initEncrypt() threw exception: " + e.toString()); - return null; - } - - } - /** * Services an archival request from netkey. * <P> @@ -371,7 +352,6 @@ public class NetkeyKeygenService implements IService { wrapped_des_key = null; boolean archive = true; - PK11SymKey sk = null; byte[] publicKeyData = null; ; String PubKey = ""; @@ -456,12 +436,9 @@ public class NetkeyKeygenService implements IService { (wrapped_des_key.length > 0)) { WrappingParams wrapParams = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, + SymmetricKey.DES3, KeyGenAlgorithm.DES3, 0, KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); - - // unwrap the DES key - sk = (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key, wrapParams); + KeyWrapAlgorithm.DES3_CBC_PAD, EncryptionUnit.IV, EncryptionUnit.IV); /* XXX could be done in HSM*/ KeyPair keypair = null; @@ -530,24 +507,29 @@ public class NetkeyKeygenService implements IService { CMS.debug("NetkeyKeygenService: got private key"); } - if (sk == null) { - CMS.debug("NetkeyKeygenService: no DES key"); + // unwrap the DES key + PK11SymKey sk = null; + try { + sk = (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key, wrapParams); + CMS.debug("NetkeyKeygenService: received DES key"); + } catch (Exception e) { + CMS.debug("NetkeyKeygenService: no DES key: " + e); request.setExtData(IRequest.RESULT, Integer.valueOf(4)); return false; - } else { - CMS.debug("NetkeyKeygenService: received DES key"); } // 3 wrapping should be done in HSM // wrap private key with DES - KeyWrapper symWrap = - keygenToken.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); CMS.debug("NetkeyKeygenService: wrapper token=" + keygenToken.getName()); - CMS.debug("NetkeyKeygenService: got key wrapper"); - CMS.debug("NetkeyKeygenService: key transport key is on slot: " + sk.getOwningToken().getName()); - symWrap.initWrap(sk, algParam); - byte wrapped[] = symWrap.wrap((PrivateKey) privKey); + + byte[] wrapped = CryptoUtil.wrapUsingSymmetricKey( + keygenToken, + sk, + (PrivateKey) privKey, + algParam, + KeyWrapAlgorithm.DES3_CBC_PAD); + /* CMS.debug("NetkeyKeygenService: wrap called"); CMS.debug(wrapped); @@ -686,6 +668,9 @@ public class NetkeyKeygenService implements IService { CMS.debug("NetkeyKeygenService: serialNo null"); return false; } + + rec.setWrappingParams(mStorageUnit.getWrappingParams()); + CMS.debug("NetkeyKeygenService: before addKeyRecord"); rec.set(KeyRecord.ATTR_ID, serialNo); request.setExtData(ATTR_KEY_RECORD, serialNo); diff --git a/base/kra/src/com/netscape/kra/RecoveryService.java b/base/kra/src/com/netscape/kra/RecoveryService.java index 70b5e57a7..c89e2f388 100644 --- a/base/kra/src/com/netscape/kra/RecoveryService.java +++ b/base/kra/src/com/netscape/kra/RecoveryService.java @@ -274,7 +274,10 @@ public class RecoveryService implements IService { try { mKRA.getStorageKeyUnit().unwrap( - keyRecord.getPrivateKeyData(), null); + keyRecord.getPrivateKeyData(), + null, + false, + keyRecord.getWrappingParams(mKRA.getStorageKeyUnit().getOldWrappingParams())); } catch (Exception e) { throw new EBaseException("Failed to unwrap private key", e); } @@ -393,33 +396,21 @@ public class RecoveryService implements IService { mStorageUnit.login(creds); } - /* wrapped retrieve session key and private key */ - DerValue val = new DerValue(keyRecord.getPrivateKeyData()); - DerInputStream in = val.data; - DerValue dSession = in.getDerValue(); - byte session[] = dSession.getOctetString(); - DerValue dPri = in.getDerValue(); - byte pri[] = dPri.getOctetString(); - - /* debug */ - byte publicKeyData[] = keyRecord.getPublicKeyData(); PublicKey pubkey = null; try { - pubkey = X509Key.parsePublicKey(new DerValue(publicKeyData)); + pubkey = X509Key.parsePublicKey(new DerValue(keyRecord.getPublicKeyData())); } catch (Exception e) { CMS.debug("RecoverService: after parsePublicKey:" + e.toString()); throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "public key parsing failure")); } - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + PrivateKey privKey = null; try { privKey = mStorageUnit.unwrap( - session, - keyRecord.getAlgorithm(), - iv, - pri, - pubkey); - + keyRecord.getPrivateKeyData(), + pubkey, + false, + keyRecord.getWrappingParams(mKRA.getStorageKeyUnit().getOldWrappingParams())); } catch (Exception e) { mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND")); throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", @@ -564,7 +555,9 @@ public class RecoveryService implements IService { mKRA.log(ILogger.LL_INFO, "KRA decrypts internal private"); try { - byte[] privateKeyData = mStorageUnit.decryptInternalPrivate(keyRecord.getPrivateKeyData()); + byte[] privateKeyData = mStorageUnit.decryptInternalPrivate( + keyRecord.getPrivateKeyData(), + keyRecord.getWrappingParams(mKRA.getStorageKeyUnit().getOldWrappingParams())); if (CMS.getConfigStore().getBoolean("kra.keySplitting")) { mStorageUnit.logout(); diff --git a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java index 1c94bca6e..598ed0232 100644 --- a/base/kra/src/com/netscape/kra/SecurityDataProcessor.java +++ b/base/kra/src/com/netscape/kra/SecurityDataProcessor.java @@ -1,11 +1,7 @@ package com.netscape.kra; import java.io.ByteArrayOutputStream; -import java.io.CharConversionException; -import java.io.IOException; import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.AlgorithmParameterSpec; @@ -16,21 +12,17 @@ import java.util.Random; import javax.crypto.spec.RC2ParameterSpec; import org.dogtagpki.server.kra.rest.KeyRequestService; -import org.mozilla.jss.CryptoManager; import org.mozilla.jss.asn1.OCTET_STRING; -import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.PBEAlgorithm; import org.mozilla.jss.crypto.PBEKeyGenParams; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.SymmetricKey; -import org.mozilla.jss.crypto.TokenException; import org.mozilla.jss.pkcs12.PasswordConverter; import org.mozilla.jss.pkcs7.ContentInfo; import org.mozilla.jss.pkcs7.EncryptedContentInfo; @@ -54,6 +46,7 @@ import com.netscape.certsrv.security.IStorageKeyUnit; import com.netscape.certsrv.security.ITransportKeyUnit; import com.netscape.certsrv.security.WrappingParams; import com.netscape.cmscore.dbs.KeyRecord; +import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.util.Utils; import netscape.security.util.DerValue; @@ -179,7 +172,8 @@ public class SecurityDataProcessor { wrappedSessionKey, algStr, sparams, - secdata); + secdata, + null); } catch (Exception e) { throw new EBaseException("Can't decrypt symm key using allEncDecrypt_archival : true ."); @@ -215,7 +209,8 @@ public class SecurityDataProcessor { wrappedSessionKey, algStr, sparams, - secdata); + secdata, + null); } catch (Exception e) { throw new EBaseException("Can't decrypt passphrase.", e); } @@ -290,6 +285,16 @@ public class SecurityDataProcessor { rec.set(KeyRecord.ATTR_REALM, realm); } + try { + rec.setWrappingParams(storageUnit.getWrappingParams()); + } catch (Exception e) { + kra.log(ILogger.LL_FAILURE, + "Failed to store wrapping parameters: " + e); + auditArchivalRequestProcessed(auditSubjectID, ILogger.FAILURE, requestId, + clientKeyId, null, "Failed to store wrapping parameters"); + throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"), e); + } + CMS.debug("KRA adding Security Data key record " + serialNo); keyRepository.addKeyRecord(rec); @@ -307,11 +312,7 @@ public class SecurityDataProcessor { CMS.debug("SecurityDataService.recover(): start"); - //Pave the way for allowing generated IV vector - byte iv[]= null; - byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; byte iv_in[] = null; - IConfigStore config = null; try { @@ -360,18 +361,6 @@ public class SecurityDataProcessor { return false; } - //Create the return IV if needed. - iv = new byte[8]; - - try { - Random rnd = new Random(); - rnd.nextBytes(iv); - } catch (Exception e) { - iv = iv_default; - } - - String ivStr = Utils.base64encode(iv); - KeyRecord keyRecord = (KeyRecord) keyRepository.readKeyRecord(serialno); String dataType = (String) keyRecord.get(IKeyRecord.ATTR_DATA_TYPE); @@ -406,7 +395,11 @@ public class SecurityDataProcessor { byte[] privateKeyData = keyRecord.getPrivateKeyData(); PublicKey publicKey = X509Key.parsePublicKey(new DerValue(publicKeyData)); - privateKey = storageUnit.unwrap_temp(privateKeyData, publicKey); + privateKey = storageUnit.unwrap( + privateKeyData, + publicKey, + true, + keyRecord.getWrappingParams(storageUnit.getOldWrappingParams())); } } catch (Exception e) { @@ -419,10 +412,32 @@ public class SecurityDataProcessor { CryptoToken ct = transportUnit.getToken(); - WrappingParams wrapParams = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, - KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); + String payloadEncryptOID = (String) params.get(IRequest.SECURITY_DATA_PL_ENCRYPTION_OID); + String payloadWrapName = (String) params.get(IRequest.SECURITY_DATA_PL_WRAPPING_NAME); + String transportKeyAlgo = transportUnit.getCertificate().getPublicKey().getAlgorithm(); + + byte[] iv = generate_iv(); + String ivStr = Utils.base64encode(iv); + + WrappingParams wrapParams = null; + if (payloadEncryptOID == null) { + wrapParams = transportUnit.getOldWrappingParams(); + wrapParams.setPayloadEncryptionIV(new IVParameterSpec(iv)); + wrapParams.setPayloadWrappingIV(new IVParameterSpec(iv)); + } else { + try { + wrapParams = new WrappingParams( + payloadEncryptOID, + payloadWrapName, + transportKeyAlgo, + new IVParameterSpec(iv), + null); + } catch (Exception e) { + auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(), + "Cannot generate wrapping params"); + throw new EBaseException("Cannot generate wrapping params: " + e, e); + } + } byte[] key_data = null; String pbeWrappedData = null; @@ -435,8 +450,14 @@ public class SecurityDataProcessor { try { unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.DECRYPT, wrapParams); - unwrappedPass = decryptWithSymmetricKey(ct, unwrappedSess, wrappedPassPhrase, - new IVParameterSpec(iv_in), wrapParams); + + unwrappedPass = CryptoUtil.decryptUsingSymmetricKey( + ct, + wrapParams.getPayloadEncryptionIV(), + wrappedPassPhrase, + unwrappedSess, + wrapParams.getPayloadEncryptionAlgorithm()); + String passStr = new String(unwrappedPass, "UTF-8"); pass = new Password(passStr.toCharArray()); passStr = null; @@ -499,13 +520,21 @@ public class SecurityDataProcessor { CMS.debug("SecurityDataProcessor.recover(): encrypt symmetric key with session key as per allowEncDecrypt_recovery: true."); unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.ENCRYPT, wrapParams); - key_data = encryptWithSymmetricKey(ct, unwrappedSess, unwrappedSecData, - new IVParameterSpec(iv), wrapParams); - + key_data = CryptoUtil.encryptUsingSymmetricKey( + ct, + unwrappedSess, + unwrappedSecData, + wrapParams.getPayloadEncryptionAlgorithm(), + wrapParams.getPayloadEncryptionIV()); } else { unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.WRAP, wrapParams); - key_data = wrapWithSymmetricKey(ct, unwrappedSess, symKey, new IVParameterSpec(iv), wrapParams); + key_data = CryptoUtil.wrapUsingSymmetricKey( + ct, + unwrappedSess, + symKey, + wrapParams.getPayloadWrappingIV(), + wrapParams.getPayloadWrapAlgorithm()); } } catch (Exception e) { @@ -520,8 +549,12 @@ public class SecurityDataProcessor { unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.ENCRYPT, wrapParams); - key_data = encryptWithSymmetricKey(ct, unwrappedSess, unwrappedSecData, - new IVParameterSpec(iv), wrapParams); + key_data = CryptoUtil.encryptUsingSymmetricKey( + ct, + unwrappedSess, + unwrappedSecData, + wrapParams.getPayloadEncryptionAlgorithm(), + wrapParams.getPayloadEncryptionIV()); } catch (Exception e) { auditRecoveryRequestProcessed(auditSubjectID, ILogger.FAILURE, requestID, serialno.toString(), "Cannot encrypt passphrase"); @@ -535,12 +568,23 @@ public class SecurityDataProcessor { CMS.debug("SecurityDataProcessor.recover(): encrypt symmetric key."); unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.ENCRYPT, wrapParams); - key_data = encryptWithSymmetricKey(ct, unwrappedSess, unwrappedSecData, - new IVParameterSpec(iv), wrapParams); + + key_data = CryptoUtil.encryptUsingSymmetricKey( + ct, + unwrappedSess, + unwrappedSecData, + wrapParams.getPayloadEncryptionAlgorithm(), + wrapParams.getPayloadEncryptionIV()); + } else { unwrappedSess = transportUnit.unwrap_session_key(ct, wrappedSessKey, SymmetricKey.Usage.WRAP, wrapParams); - key_data = wrapWithSymmetricKey(ct, unwrappedSess, privateKey, new IVParameterSpec(iv), wrapParams); + key_data = CryptoUtil.wrapUsingSymmetricKey( + ct, + unwrappedSess, + privateKey, + wrapParams.getPayloadWrappingIV(), + wrapParams.getPayloadWrapAlgorithm()); } } catch (Exception e) { @@ -566,42 +610,20 @@ public class SecurityDataProcessor { return false; //return true ? TODO } - private byte[] decryptWithSymmetricKey(CryptoToken ct, SymmetricKey wrappingKey, byte[] data, IVParameterSpec iv, - WrappingParams params) throws Exception { - Cipher decryptor = ct.getCipherContext(params.getPayloadEncryptionAlgorithm()); - if (decryptor == null) - throw new IOException("Failed to create decryptor"); - decryptor.initDecrypt(wrappingKey, iv); - return decryptor.doFinal(data); - } - - private byte[] wrapWithSymmetricKey(CryptoToken ct, SymmetricKey wrappingKey, SymmetricKey data, - IVParameterSpec iv, WrappingParams params) throws Exception { - KeyWrapper wrapper = ct.getKeyWrapper(params.getPayloadWrapAlgorithm()); - if (wrapper == null) - throw new IOException("Failed to create key wrapper"); - wrapper.initWrap(wrappingKey, iv); - return wrapper.wrap(data); - } - - private byte[] wrapWithSymmetricKey(CryptoToken ct, SymmetricKey wrappingKey, PrivateKey data, - IVParameterSpec iv, WrappingParams params) throws Exception { - KeyWrapper wrapper = ct.getKeyWrapper(params.getPayloadWrapAlgorithm()); - if (wrapper == null) - throw new IOException("Failed to create key wrapper"); - wrapper.initWrap(wrappingKey, iv); - return wrapper.wrap(data); - } - - private byte[] encryptWithSymmetricKey(CryptoToken ct, SymmetricKey wrappingKey, byte[] data, IVParameterSpec iv, - WrappingParams params) throws Exception { - Cipher encryptor = ct.getCipherContext(params.getPayloadEncryptionAlgorithm()); - - if (encryptor == null) - throw new IOException("Failed to create cipher"); + private byte[] generate_iv() { + //TODO(alee) Fix this -- this will only work for DES3. Needs to be based on algorithm. + // Is there a function in JSS for this? Also note that the iv generated here is actually + // used for both encryption and wrapping algorithms above. + byte[] iv = new byte[8]; + byte iv_default[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - encryptor.initEncrypt(wrappingKey, iv); - return encryptor.doFinal(data); + try { + Random rnd = new Random(); + rnd.nextBytes(iv); + } catch (Exception e) { + iv = iv_default; + } + return iv; } public SymmetricKey recoverSymKey(KeyRecord keyRecord) @@ -612,7 +634,8 @@ public class SecurityDataProcessor { storageUnit.unwrap( keyRecord.getPrivateKeyData(), KeyRequestService.SYMKEY_TYPES.get(keyRecord.getAlgorithm()), - keyRecord.getKeySize()); + keyRecord.getKeySize(), + keyRecord.getWrappingParams(storageUnit.getOldWrappingParams())); return symKey; } catch (Exception e) { throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", @@ -623,7 +646,9 @@ public class SecurityDataProcessor { public byte[] recoverSecurityData(KeyRecord keyRecord) throws EBaseException { try { - return storageUnit.decryptInternalPrivate(keyRecord.getPrivateKeyData()); + return storageUnit.decryptInternalPrivate( + keyRecord.getPrivateKeyData(), + keyRecord.getWrappingParams(storageUnit.getOldWrappingParams())); } catch (Exception e) { CMS.debug("Failed to recover security data: " + e); throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", @@ -637,9 +662,7 @@ public class SecurityDataProcessor { int iterationCount, KeyGenerator.CharToByteConverter charToByteConverter, SymmetricKey symKey, PrivateKey privateKey, CryptoToken token) - throws CryptoManager.NotInitializedException, NoSuchAlgorithmException, - InvalidKeyException, InvalidAlgorithmParameterException, TokenException, - CharConversionException { + throws Exception { if (keyGenAlg == null) { throw new NoSuchAlgorithmException("Key generation algorithm is NULL"); @@ -665,14 +688,13 @@ public class SecurityDataProcessor { kg.generatePBE_IV()); } - KeyWrapper wrapper = token.getKeyWrapper( - KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initWrap(key, params); byte[] encrypted = null; if (symKey != null) { - encrypted = wrapper.wrap(symKey); + encrypted = CryptoUtil.wrapUsingSymmetricKey(token, key, symKey, (IVParameterSpec) params, + KeyWrapAlgorithm.DES3_CBC_PAD); } else if (privateKey != null) { - encrypted = wrapper.wrap(privateKey); + encrypted = CryptoUtil.wrapUsingSymmetricKey(token, key, privateKey, (IVParameterSpec) params, + KeyWrapAlgorithm.DES3_CBC_PAD); } if (encrypted == null) { //TODO - think about the exception to be thrown diff --git a/base/kra/src/com/netscape/kra/StorageKeyUnit.java b/base/kra/src/com/netscape/kra/StorageKeyUnit.java index 83f3e2a79..8b4c801fb 100644 --- a/base/kra/src/com/netscape/kra/StorageKeyUnit.java +++ b/base/kra/src/com/netscape/kra/StorageKeyUnit.java @@ -36,6 +36,7 @@ import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IllegalBlockSizeException; +import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; import org.mozilla.jss.crypto.KeyWrapper; @@ -60,9 +61,14 @@ import com.netscape.certsrv.kra.IShare; import com.netscape.certsrv.logging.ILogger; import com.netscape.certsrv.security.Credential; import com.netscape.certsrv.security.IStorageKeyUnit; +import com.netscape.certsrv.security.WrappingParams; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.util.Utils; +import netscape.security.util.DerInputStream; +import netscape.security.util.DerOutputStream; +import netscape.security.util.DerValue; + /** * A class represents a storage key unit. Currently, this * is implemented with cryptix, the final implementation @@ -99,6 +105,7 @@ public class StorageKeyUnit extends EncryptionUnit implements public static final String PROP_KEYDB = "keydb"; public static final String PROP_CERTDB = "certdb"; public static final String PROP_MN = "mn"; + public static final String PROP_OLD_WRAPPING = "useOldWrapping"; /** * Constructs this token. @@ -123,6 +130,17 @@ public class StorageKeyUnit extends EncryptionUnit implements throw new EBaseException(CMS.getUserMessage("CMS_INVALID_OPERATION")); } + public WrappingParams getWrappingParams() throws EBaseException { + if (mConfig.getBoolean(PROP_OLD_WRAPPING, false)) { + return this.getOldWrappingParams(); + } + + return new WrappingParams( + SymmetricKey.AES, KeyGenAlgorithm.AES, 256, + KeyWrapAlgorithm.RSA, EncryptionAlgorithm.AES_256_CBC_PAD, + KeyWrapAlgorithm.AES_KEY_WRAP_PAD, IV2, null); + } + /** * return true if byte arrays are equal, false otherwise */ @@ -448,30 +466,16 @@ public class StorageKeyUnit extends EncryptionUnit implements try { // move public & private to config/storage.dat // delete private key - KeyWrapper wrapper = token.getKeyWrapper( + return CryptoUtil.wrapUsingSymmetricKey( + token, + sk, + pri, + IV, KeyWrapAlgorithm.DES3_CBC_PAD); - - // next to randomly generate a symmetric - // password - - wrapper.initWrap(sk, IV); - return wrapper.wrap(pri); - } catch (TokenException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", - "wrapStorageKey:" + - e.toString())); - } catch (NoSuchAlgorithmException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", - "wrapStorageKey:" + - e.toString())); - } catch (InvalidKeyException e) { - throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", - "wrapStorageKey:" + - e.toString())); - } catch (InvalidAlgorithmParameterException e) { + } catch (Exception e) { throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_KEY_1", "wrapStorageKey:" + - e.toString())); + e.toString()), e); } } @@ -1001,4 +1005,212 @@ public class StorageKeyUnit extends EncryptionUnit implements return true; } + /**************************************************************************************** + * Methods to encrypt and store secrets in the database + ***************************************************************************************/ + + public byte[] encryptInternalPrivate(byte priKey[]) throws Exception { + try (DerOutputStream out = new DerOutputStream()) { + CMS.debug("EncryptionUnit.encryptInternalPrivate"); + CryptoToken internalToken = getInternalToken(); + + WrappingParams params = getWrappingParams(); + + // (1) generate session key + SymmetricKey sk = CryptoUtil.generateKey( + internalToken, + params.getSkKeyGenAlgorithm(), + params.getSkLength(), + null, + false); + + // (2) wrap private key with session key + byte[] pri = CryptoUtil.encryptUsingSymmetricKey( + internalToken, + sk, + priKey, + params.getPayloadEncryptionAlgorithm(), + params.getPayloadEncryptionIV()); + + // (3) wrap session with storage public + byte[] session = CryptoUtil.wrapUsingPublicKey( + internalToken, + getPublicKey(), + sk, + params.getSkWrapAlgorithm()); + + // use MY own structure for now: + // SEQUENCE { + // encryptedSession OCTET STRING, + // encryptedPrivate OCTET STRING + // } + + DerOutputStream tmp = new DerOutputStream(); + + tmp.putOctetString(session); + tmp.putOctetString(pri); + out.write(DerValue.tag_Sequence, tmp); + + return out.toByteArray(); + } + } + + public byte[] wrap(PrivateKey privKey) throws Exception { + return _wrap(privKey,null); + } + + public byte[] wrap(SymmetricKey symmKey) throws Exception { + return _wrap(null,symmKey); + } + + /*** + * Internal wrap, accounts for either private or symmetric key + */ + private byte[] _wrap(PrivateKey priKey, SymmetricKey symmKey) throws Exception { + try (DerOutputStream out = new DerOutputStream()) { + if ((priKey == null && symmKey == null) || (priKey != null && symmKey != null)) { + return null; + } + CMS.debug("EncryptionUnit.wrap interal."); + WrappingParams params = getWrappingParams(); + CryptoToken token = getToken(); + + SymmetricKey.Usage usages[] = new SymmetricKey.Usage[2]; + usages[0] = SymmetricKey.Usage.WRAP; + usages[1] = SymmetricKey.Usage.UNWRAP; + + // (1) generate session key + SymmetricKey sk = CryptoUtil.generateKey( + token, + params.getSkKeyGenAlgorithm(), + params.getSkLength(), + usages, + true); + + // (2) wrap private key with session key + // KeyWrapper wrapper = internalToken.getKeyWrapper( + + byte pri[] = null; + + if (priKey != null) { + pri = CryptoUtil.wrapUsingSymmetricKey( + token, + sk, + priKey, + params.getPayloadWrappingIV(), + params.getPayloadWrapAlgorithm()); + } else if (symmKey != null) { + pri = CryptoUtil.wrapUsingSymmetricKey( + token, + sk, + symmKey, + params.getPayloadWrappingIV(), + params.getPayloadWrapAlgorithm()); + } + + CMS.debug("EncryptionUnit:wrap() privKey wrapped"); + + byte[] session = CryptoUtil.wrapUsingPublicKey( + token, + getPublicKey(), + sk, + params.getSkWrapAlgorithm()); + CMS.debug("EncryptionUnit:wrap() session key wrapped"); + + // use MY own structure for now: + // SEQUENCE { + // encryptedSession OCTET STRING, + // encryptedPrivate OCTET STRING + // } + + DerOutputStream tmp = new DerOutputStream(); + + tmp.putOctetString(session); + tmp.putOctetString(pri); + out.write(DerValue.tag_Sequence, tmp); + + return out.toByteArray(); + } + } + + /**************************************************************************************** + * Methods to decrypt and retrieve secrets from the database + ***************************************************************************************/ + + public byte[] decryptInternalPrivate(byte wrappedKeyData[], WrappingParams params) + throws Exception { + CMS.debug("EncryptionUnit.decryptInternalPrivate"); + DerValue val = new DerValue(wrappedKeyData); + // val.tag == DerValue.tag_Sequence + DerInputStream in = val.data; + DerValue dSession = in.getDerValue(); + byte session[] = dSession.getOctetString(); + DerValue dPri = in.getDerValue(); + byte pri[] = dPri.getOctetString(); + + CryptoToken token = getToken(); + + // (1) unwrap the session key + CMS.debug("decryptInternalPrivate(): getting key wrapper on slot:" + token.getName()); + SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.DECRYPT, params); + + // (2) decrypt the private key + return CryptoUtil.decryptUsingSymmetricKey( + token, + params.getPayloadEncryptionIV(), + pri, + sk, + params.getPayloadEncryptionAlgorithm()); + } + + public SymmetricKey unwrap(byte wrappedKeyData[], SymmetricKey.Type algorithm, int keySize, + WrappingParams params) throws Exception { + DerValue val = new DerValue(wrappedKeyData); + // val.tag == DerValue.tag_Sequence + DerInputStream in = val.data; + DerValue dSession = in.getDerValue(); + byte session[] = dSession.getOctetString(); + DerValue dPri = in.getDerValue(); + byte pri[] = dPri.getOctetString(); + + CryptoToken token = getToken(); + // (1) unwrap the session key + SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.UNWRAP, params); + + // (2) unwrap the session-wrapped-symmetric key + return CryptoUtil.unwrap( + token, + algorithm, + keySize, + SymmetricKey.Usage.UNWRAP, + sk, + pri, + params.getPayloadWrapAlgorithm(), + params.getPayloadWrappingIV()); + } + + public PrivateKey unwrap(byte wrappedKeyData[], PublicKey pubKey, boolean temporary, WrappingParams params) + throws Exception { + DerValue val = new DerValue(wrappedKeyData); + // val.tag == DerValue.tag_Sequence + DerInputStream in = val.data; + DerValue dSession = in.getDerValue(); + byte session[] = dSession.getOctetString(); + DerValue dPri = in.getDerValue(); + byte pri[] = dPri.getOctetString(); + + CryptoToken token = getToken(); + // (1) unwrap the session key + SymmetricKey sk = unwrap_session_key(token, session, SymmetricKey.Usage.UNWRAP, params); + + // (2) unwrap the private key + return CryptoUtil.unwrap( + token, + pubKey, + temporary, + sk, + pri, + params.getPayloadWrapAlgorithm(), + params.getPayloadWrappingIV()); + } } diff --git a/base/kra/src/com/netscape/kra/SymKeyGenService.java b/base/kra/src/com/netscape/kra/SymKeyGenService.java index 7d42cb45b..94301b662 100644 --- a/base/kra/src/com/netscape/kra/SymKeyGenService.java +++ b/base/kra/src/com/netscape/kra/SymKeyGenService.java @@ -17,10 +17,7 @@ // --- END COPYRIGHT BLOCK --- package com.netscape.kra; -import java.io.CharConversionException; import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -28,9 +25,7 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.KeyGenAlgorithm; -import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.SymmetricKey; -import org.mozilla.jss.crypto.TokenException; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; @@ -46,6 +41,7 @@ import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.security.IStorageKeyUnit; import com.netscape.cms.servlet.key.KeyRequestDAO; import com.netscape.cmscore.dbs.KeyRecord; +import com.netscape.cmsutil.crypto.CryptoUtil; /** * This implementation implements SecurityData archival operations. @@ -154,21 +150,13 @@ public class SymKeyGenService implements IService { SymmetricKey sk = null; try { - KeyGenerator kg = token.getKeyGenerator(kgAlg); - kg.setKeyUsages(keyUsages); - kg.temporaryKeys(true); - if (kgAlg == KeyGenAlgorithm.AES || kgAlg == KeyGenAlgorithm.RC4 - || kgAlg == KeyGenAlgorithm.RC2) { - kg.initialize(keySize); - } - sk = kg.generate(); + sk = CryptoUtil.generateKey(token, kgAlg, keySize, keyUsages, true); CMS.debug("SymKeyGenService:wrap() session key generated on slot: " + token.getName()); - } catch (TokenException | IllegalStateException | CharConversionException | NoSuchAlgorithmException - | InvalidAlgorithmParameterException e) { + } catch (Exception e) { CMS.debugStackTrace(); auditSymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(), clientKeyId, null, "Failed to generate symmetric key"); - throw new EBaseException("Errors in generating symmetric key: " + e); + throw new EBaseException("Errors in generating symmetric key: " + e, e); } byte[] publicKey = null; @@ -224,6 +212,16 @@ public class SymKeyGenService implements IService { rec.set(KeyRecord.ATTR_REALM, realm); } + try { + rec.setWrappingParams(mStorageUnit.getWrappingParams()); + } catch (Exception e) { + mKRA.log(ILogger.LL_FAILURE, + "Failed to store wrapping parameters: " + e); + auditSymKeyGenRequestProcessed(auditSubjectID, ILogger.FAILURE, request.getRequestId(), + clientKeyId, null, "Failed to store wraping parameters."); + throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE"), e); + } + CMS.debug("KRA adding Security Data key record " + serialNo); storage.addKeyRecord(rec); diff --git a/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java index 5ad8044d7..8abf92046 100644 --- a/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java +++ b/base/kra/src/com/netscape/kra/TokenKeyRecoveryService.java @@ -27,13 +27,11 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.util.Hashtable; -import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyWrapAlgorithm; -import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.PrivateKey.Type; import org.mozilla.jss.crypto.SymmetricKey; @@ -54,6 +52,7 @@ import com.netscape.certsrv.security.IStorageKeyUnit; import com.netscape.certsrv.security.ITransportKeyUnit; import com.netscape.certsrv.security.WrappingParams; import com.netscape.cmscore.dbs.KeyRecord; +import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.util.Cert; import netscape.security.util.BigInt; @@ -170,23 +169,6 @@ public class TokenKeyRecoveryService implements IService { } } - // this encrypts bytes with a symmetric key - public byte[] encryptIt(byte[] toBeEncrypted, SymmetricKey symKey, CryptoToken token, - IVParameterSpec IV) { - try { - Cipher cipher = token.getCipherContext( - EncryptionAlgorithm.DES3_CBC_PAD); - - cipher.initEncrypt(symKey, IV); - byte pri[] = cipher.doFinal(toBeEncrypted); - return pri; - } catch (Exception e) { - CMS.debug("initEncrypt() threw exception: " + e.toString()); - return null; - } - - } - /** * Processes a recovery request. The method reads * the key record from the database, and tries to recover the @@ -273,18 +255,17 @@ public class TokenKeyRecoveryService implements IService { (wrapped_des_key.length > 0)) { WrappingParams wrapParams = new WrappingParams( - SymmetricKey.DES3, null, KeyGenAlgorithm.DES3, 0, + SymmetricKey.DES3, KeyGenAlgorithm.DES3, 0, KeyWrapAlgorithm.RSA, EncryptionAlgorithm.DES3_CBC_PAD, - KeyWrapAlgorithm.DES3_CBC_PAD); + KeyWrapAlgorithm.DES3_CBC_PAD, EncryptionUnit.IV, EncryptionUnit.IV); // unwrap the des key - sk = (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key, wrapParams); - - if (sk == null) { + try { + sk = (PK11SymKey) mTransportUnit.unwrap_sym(wrapped_des_key, wrapParams); + CMS.debug("TokenKeyRecoveryService: received des key"); + } catch (Exception e) { CMS.debug("TokenKeyRecoveryService: no des key"); request.setExtData(IRequest.RESULT, Integer.valueOf(4)); - } else { - CMS.debug("TokenKeyRecoveryService: received des key"); } } else { CMS.debug("TokenKeyRecoveryService: not receive des key"); @@ -364,8 +345,6 @@ public class TokenKeyRecoveryService implements IService { CMS.debug("TokenKeyRecoveryService: got token slot:" + token.getName()); IVParameterSpec algParam = new IVParameterSpec(iv); - Cipher cipher = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); - KeyRecord keyRecord = null; CMS.debug("KRA reading key record"); try { @@ -512,8 +491,12 @@ public class TokenKeyRecoveryService implements IService { } //encrypt and put in private key - cipher.initEncrypt(sk, algParam); - wrapped = cipher.doFinal(privateKeyData); + wrapped = CryptoUtil.encryptUsingSymmetricKey( + token, + sk, + privateKeyData, + EncryptionAlgorithm.DES3_CBC_PAD, + algParam); } else { //allowEncDecrypt_recovery == false PrivateKey privKey = recoverKey(params, keyRecord, allowEncDecrypt_recovery); if (privKey == null) { @@ -531,11 +514,14 @@ public class TokenKeyRecoveryService implements IService { } CMS.debug("TokenKeyRecoveryService: about to wrap..."); - KeyWrapper wrapper = token.getKeyWrapper( - KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initWrap(sk, algParam); - wrapped = wrapper.wrap(privKey); + wrapped = CryptoUtil.wrapUsingSymmetricKey( + token, + sk, + privKey, + algParam, + KeyWrapAlgorithm.DES3_CBC_PAD); + iv_s = /*base64Encode(iv);*/com.netscape.cmsutil.util.Utils.SpecialEncode(iv); request.setExtData("iv_s", iv_s); } @@ -676,31 +662,21 @@ public class TokenKeyRecoveryService implements IService { } try { - /* wrapped retrieve session key and private key */ - DerValue val = new DerValue(keyRecord.getPrivateKeyData()); - DerInputStream in = val.data; - DerValue dSession = in.getDerValue(); - byte session[] = dSession.getOctetString(); - DerValue dPri = in.getDerValue(); - byte pri[] = dPri.getOctetString(); - - byte publicKeyData[] = keyRecord.getPublicKeyData(); PublicKey pubkey = null; try { - pubkey = X509Key.parsePublicKey (new DerValue(publicKeyData)); + pubkey = X509Key.parsePublicKey (new DerValue(keyRecord.getPublicKeyData())); } catch (Exception e) { CMS.debug("TokenKeyRecoverService: after parsePublicKey:"+e.toString()); throw new EKRAException(CMS.getUserMessage("CMS_KRA_RECOVERY_FAILED_1", "public key parsing failure")); } - byte iv[] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1}; + PrivateKey privKey = null; try { privKey = mStorageUnit.unwrap( - session, - keyRecord.getAlgorithm(), - iv, - pri, - pubkey); + keyRecord.getPrivateKeyData(), + pubkey, + false, + keyRecord.getWrappingParams(mStorageUnit.getOldWrappingParams())); } catch (Exception e) { CMS.debug("TokenKeyRecoveryService: recoverKey() - recovery failure"); throw new EKRAException( @@ -728,7 +704,9 @@ public class TokenKeyRecoveryService implements IService { mStorageUnit.login(creds); */ try { - return mStorageUnit.decryptInternalPrivate(keyRecord.getPrivateKeyData()); + return mStorageUnit.decryptInternalPrivate( + keyRecord.getPrivateKeyData(), + keyRecord.getWrappingParams(mStorageUnit.getOldWrappingParams())); /* mStorageUnit.logout();*/ } catch (Exception e){ mKRA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_KRA_PRIVATE_KEY_NOT_FOUND")); diff --git a/base/kra/src/com/netscape/kra/TransportKeyUnit.java b/base/kra/src/com/netscape/kra/TransportKeyUnit.java index 2efdac7ad..672cb857a 100644 --- a/base/kra/src/com/netscape/kra/TransportKeyUnit.java +++ b/base/kra/src/com/netscape/kra/TransportKeyUnit.java @@ -21,10 +21,12 @@ import java.security.PublicKey; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.ObjectNotFoundException; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.Signature; import org.mozilla.jss.crypto.SignatureAlgorithm; +import org.mozilla.jss.crypto.SymmetricKey; import org.mozilla.jss.crypto.TokenException; import com.netscape.certsrv.apps.CMS; @@ -32,6 +34,8 @@ import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.ISubsystem; import com.netscape.certsrv.security.ITransportKeyUnit; +import com.netscape.certsrv.security.WrappingParams; +import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.util.Cert; /** @@ -110,6 +114,10 @@ public class TransportKeyUnit extends EncryptionUnit implements } } + public WrappingParams getWrappingParams() { + return getOldWrappingParams(); + } + public CryptoToken getInternalToken() { try { return CryptoManager.getInstance().getInternalKeyStorageToken(); @@ -253,4 +261,122 @@ public class TransportKeyUnit extends EncryptionUnit implements throws EBaseException { // XXX } + + public SymmetricKey unwrap_sym(byte encSymmKey[], WrappingParams params) throws Exception { + return unwrap_session_key(getToken(), encSymmKey, SymmetricKey.Usage.WRAP, params); + } + + /** + * Decrypts the user private key. This is called on the transport unit. + */ + public byte[] decryptExternalPrivate(byte encSymmKey[], + String symmAlgOID, byte symmAlgParams[], byte encValue[], + org.mozilla.jss.crypto.X509Certificate transCert) + throws Exception { + + CMS.debug("EncryptionUnit.decryptExternalPrivate"); + + if (transCert == null) { + transCert = mCert; + } + CryptoToken token = getToken(transCert); + PrivateKey wrappingKey = getPrivateKey(transCert); + String priKeyAlgo = wrappingKey.getAlgorithm(); + WrappingParams params = new WrappingParams( + symmAlgOID, + null, + priKeyAlgo, + new IVParameterSpec(symmAlgParams), + null); + + SymmetricKey sk = CryptoUtil.unwrap( + token, + params.getSkType(), + 0, + SymmetricKey.Usage.DECRYPT, + wrappingKey, + encSymmKey, + params.getSkWrapAlgorithm()); + + return CryptoUtil.decryptUsingSymmetricKey( + token, + params.getPayloadEncryptionIV(), + encValue, + sk, + params.getPayloadEncryptionAlgorithm()); + } + + /** + * External unwrapping. Unwraps the symmetric key using + * the transport private key. + */ + public SymmetricKey unwrap_symmetric(byte encSymmKey[], + String symmAlgOID, byte symmAlgParams[], + byte encValue[], SymmetricKey.Type algorithm, int strength) + throws Exception { + + CryptoToken token = getToken(); + PrivateKey wrappingKey = getPrivateKey(mCert); + String priKeyAlgo = wrappingKey.getAlgorithm(); + WrappingParams params = new WrappingParams( + symmAlgOID, + null, + priKeyAlgo, + new IVParameterSpec(symmAlgParams), + null); + + // (1) unwrap the session key + SymmetricKey sk = unwrap_session_key(token, encSymmKey, SymmetricKey.Usage.UNWRAP, params); + + // (2) unwrap the session-wrapped-symmetric-key + return CryptoUtil.unwrap( + token, + algorithm, + strength, + SymmetricKey.Usage.DECRYPT, + sk, + encValue, + params.getPayloadWrapAlgorithm(), + params.getPayloadEncryptionIV()); + } + + /** + * External unwrapping. Unwraps the data using + * the transport private key. + */ + public PrivateKey unwrap(byte encSymmKey[], + String symmAlgOID, byte symmAlgParams[], + byte encValue[], PublicKey pubKey, + org.mozilla.jss.crypto.X509Certificate transCert) + throws Exception { + CryptoToken token = getToken(transCert); + PrivateKey wrappingKey = getPrivateKey(transCert); + String priKeyAlgo = wrappingKey.getAlgorithm(); + WrappingParams params = new WrappingParams( + symmAlgOID, + null, + priKeyAlgo, + new IVParameterSpec(symmAlgParams), + new IVParameterSpec(symmAlgParams)); + + // (1) unwrap the session key + SymmetricKey sk = CryptoUtil.unwrap( + token, + params.getSkType(), + 0, + SymmetricKey.Usage.UNWRAP, + wrappingKey, + encSymmKey, + params.getSkWrapAlgorithm()); + + // (2) unwrap the session-wrapped-private key + return CryptoUtil.unwrap( + token, + pubKey, + true, + sk, + encValue, + params.getPayloadWrapAlgorithm(), + params.getPayloadWrappingIV()); + } } diff --git a/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java index c65dd3971..e7f50fbc2 100644 --- a/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java +++ b/base/server/cms/src/com/netscape/cms/authentication/AgentCertAuthentication.java @@ -22,8 +22,6 @@ import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.Locale; -import netscape.security.x509.X509CertImpl; - import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authentication.AuthToken; import com.netscape.certsrv.authentication.EInvalidCredentials; @@ -46,6 +44,8 @@ import com.netscape.certsrv.usrgrp.ICertUserLocator; import com.netscape.certsrv.usrgrp.IUGSubsystem; import com.netscape.certsrv.usrgrp.IUser; +import netscape.security.x509.X509CertImpl; + /** * Certificate server agent authentication. * Maps a SSL client authenticate certificate to a user (agent) entry in the @@ -196,7 +196,7 @@ public class AgentCertAuthentication implements IAuthManager, try { user = mCULocator.locateUser(certs); } catch (EUsrGrpException e) { - throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); + throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e); } catch (netscape.ldap.LDAPException e) { throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString())); diff --git a/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java b/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java index 2bec1b68d..a9b0ccc77 100644 --- a/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java +++ b/base/server/cms/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java @@ -24,9 +24,6 @@ import java.util.Enumeration; import java.util.Locale; import java.util.StringTokenizer; -import netscape.security.x509.BasicConstraintsExtension; -import netscape.security.x509.X509CertImpl; - import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.authentication.AuthToken; import com.netscape.certsrv.authentication.EInvalidCredentials; @@ -45,6 +42,9 @@ import com.netscape.certsrv.property.IDescriptor; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.usrgrp.Certificates; +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.X509CertImpl; + /** * Certificate server SSL client authentication. * @@ -189,7 +189,7 @@ public class SSLclientCertAuthentication implements IAuthManager, } catch (Exception e) { CMS.debug("SSLclientCertAuthentication: authenticate: exception:" + e.toString()); - throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); + throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e); } } } @@ -199,7 +199,7 @@ public class SSLclientCertAuthentication implements IAuthManager, } } catch (CertificateException e) { CMS.debug(e.toString()); - throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL")); + throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"), e); } // check if certificate(s) is revoked diff --git a/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java b/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java index 7a0784c53..48a23536a 100644 --- a/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java +++ b/base/server/cms/src/com/netscape/cms/authentication/SharedSecret.java @@ -35,4 +35,8 @@ public class SharedSecret implements ISharedToken { public String getSharedToken(BigInteger serial) { return "testing"; } + + public String getSharedToken(String identification) { + return "testing"; + } } diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java index 0f3153d3d..ed2423ff1 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java +++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java @@ -845,11 +845,7 @@ public class ConfigurationUtils { return false; } - public static void restoreCertsFromP12(String p12File, String p12Pass) throws EPropertyNotFound, EBaseException, - InvalidKeyException, CertificateException, NoSuchAlgorithmException, - InvalidAlgorithmParameterException, IllegalStateException, TokenException, IllegalBlockSizeException, - BadPaddingException, NotInitializedException, NicknameConflictException, UserCertConflictException, - NoSuchItemOnTokenException, InvalidBERException, IOException { + public static void restoreCertsFromP12(String p12File, String p12Pass) throws Exception { // TODO: The PKCS #12 file is already imported in security_database.py. // This method should be removed. @@ -1018,11 +1014,7 @@ public class ConfigurationUtils { public static void importKeyCert( Vector<Vector<Object>> pkeyinfo_collection, Vector<Vector<Object>> cert_collection - ) throws IOException, CertificateException, TokenException, - NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, - IllegalStateException, - IllegalBlockSizeException, BadPaddingException, NotInitializedException, NicknameConflictException, - UserCertConflictException, NoSuchItemOnTokenException, EPropertyNotFound, EBaseException { + ) throws Exception { CMS.debug("ConfigurationUtils.importKeyCert()"); CryptoManager cm = CryptoManager.getInstance(); @@ -1072,13 +1064,10 @@ public class ConfigurationUtils { } // encrypt private key - KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3); - SymmetricKey sk = kg.generate(); + SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; IVParameterSpec param = new IVParameterSpec(iv); - Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); - c.initEncrypt(sk, param); - byte[] encpkey = c.doFinal(pkey); + byte[] encpkey = CryptoUtil.encryptUsingSymmetricKey(token, sk, pkey, EncryptionAlgorithm.DES3_CBC_PAD, param); // unwrap private key to load into database KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); diff --git a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java index 256f72879..c471a2869 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java +++ b/base/server/cms/src/com/netscape/cms/servlet/key/KeyRecordParser.java @@ -46,6 +46,19 @@ public class KeyRecordParser { public final static String OUT_RECOVERED_BY = "recoveredBy"; public final static String OUT_RECOVERED_ON = "recoveredOn"; + /* parameters to populate WrappingParams */ + public final static String OUT_SK_TYPE = "sessionKeyType"; + public final static String OUT_SK_KEYGEN_ALGORITHM = "sessionKeyKeyGenAlgorithm"; + public final static String OUT_SK_LENGTH = "sessionKeyLength"; + public final static String OUT_SK_WRAP_ALGORITHM = "sessionKeyWrapAlgorithm"; + public final static String OUT_PL_WRAP_ALGORITHM = "payloadWrapAlgorithm"; + public final static String OUT_PL_WRAP_IV = "payloadWrapIV"; + public final static String OUT_PL_ENCRYPTION_ALGORITHM = "payloadEncryptionAlgorithm"; + public final static String OUT_PL_ENCRYPTION_MODE = "payloadEncryptionMode"; + public final static String OUT_PL_ENCRYPTION_PADDING = "payloadEncryptionPadding"; + public final static String OUT_PL_ENCRYPTION_IV = "payloadEncryptionIV"; + public final static String OUT_PL_ENCRYPTION_OID = "payloadEncryptionOID"; + /** * Fills key record into argument block. */ diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java b/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java new file mode 100644 index 000000000..f16481be5 --- /dev/null +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/GPParams.java @@ -0,0 +1,108 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2013 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cms.servlet.tks; + + +//Simple class used to hold scp03 related settings in TKS keyset config block +// Ex: tks.defKeySet.prot3.divers=emv +// tks.defKeySet.prot3.diversVer1Keys=emv + +// Will probably be extended to allow params for future tokens + +public class GPParams { + + public static String DIVER_EMV = "emv"; + public static String DIVER_NONE = "none"; + public static String DIVER_VISA2 = "visa2"; + public static String NIST_SP800 = "nistsp_800"; + + public GPParams() { + } + + // Diversification scheme for all keysets after 1 + private String diversificationScheme; + //Diversification scheme for just version one or developer keys + private String version1DiversificationScheme; + + public boolean isDiversEmv() { + if (DIVER_EMV.equalsIgnoreCase(diversificationScheme)) + return true; + else + return false; + } + + public boolean isDiversVisa2() { + if (DIVER_VISA2.equalsIgnoreCase(diversificationScheme)) + return true; + else + return false; + } + + public boolean isDiversNone() { + if (DIVER_NONE.equalsIgnoreCase(diversificationScheme)) + return true; + else + return false; + } + + public boolean isVer1DiversEmv() { + if (DIVER_EMV.equalsIgnoreCase(version1DiversificationScheme)) + return true; + else + return false; + } + + public boolean isVer1DiversVisa2() { + if (DIVER_VISA2.equalsIgnoreCase(version1DiversificationScheme)) + return true; + else + return false; + + } + + public boolean isVer1DiversNone() { + if (DIVER_NONE.equalsIgnoreCase(version1DiversificationScheme)) + return true; + else + return false; + } + + public void setDiversificationScheme(String scheme) { + diversificationScheme = scheme; + } + + public String getDiversificationScheme() { + return diversificationScheme; + } + + public String getVersion1DiversificationScheme() { + return version1DiversificationScheme; + } + + public void setVersion1DiversificationScheme(String version1DiversificationScheme) { + this.version1DiversificationScheme = version1DiversificationScheme; + } + + public String toString() { + String output = " Version1 Diversification Scheme: " + version1DiversificationScheme + " All other versions : " + + diversificationScheme; + + return output; + } + +} diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java index 0407e2934..e7b183b4e 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/KDF.java @@ -41,9 +41,64 @@ public class KDF { /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */ /* E */0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe, }; - public static byte[] getDiversificationData(byte[] context, String type) throws EBaseException { + //Add the emv diversification method, used in SCP03 g&d card. + public static byte[] getDiversificationData_EMV(byte[] context, String type) throws EBaseException { - String method = "KDF.getDiversificationData:"; + String method = "KDF.getDiversificationData_EMV:"; + + CMS.debug(method + " entering ..."); + + if (context == null || type == null) { + throw new EBaseException(method + "Invalid input parameters!"); + } + + byte[] KDC = new byte[SecureChannelProtocol.DES2_LENGTH]; + + KDC[0] = context[4 + 0]; + KDC[1] = context[4 + 1]; + KDC[2] = context[4 + 2]; + KDC[3] = context[4 + 3]; + KDC[4] = context[4 + 4]; + KDC[5] = context[4 + 5]; + KDC[6] = (byte) 0xF0; + + KDC[7] = 0x1; + + KDC[8] = context[4 + 0]; + KDC[9] = context[4 + 1]; + KDC[10] = context[4 + 2]; + KDC[11] = context[4 +3]; + KDC[12] = context[4 + 4]; + KDC[13] = context[4 + 5]; + KDC[14] = (byte) 0x0f; + + KDC[15] = 0x1; + + if (type.equals(SecureChannelProtocol.encType)) + return KDC; + + KDC[7] = 0x02; + KDC[15] = 0x02; + if (type.equals(SecureChannelProtocol.macType)) + return KDC; + + KDC[7] = 0x03; + KDC[15] = 0x03; + if (type.equals(SecureChannelProtocol.kekType)) + return KDC; + + KDC[7] = 0x04; + KDC[15] = 0x04; + if (type.equals(SecureChannelProtocol.rmacType)) + return KDC; + return KDC; + + } + + //Standard visa2 diversification method + public static byte[] getDiversificationData_VISA2(byte[] context, String type) throws EBaseException { + + String method = "KDF.getDiversificationData_VISA2:"; CMS.debug(method + " entering ..."); diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java index e392ce1a3..ad4a370c2 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/NistSP800_108KDF.java @@ -1,13 +1,24 @@ package com.netscape.cms.servlet.tks; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.mozilla.jss.crypto.BadPaddingException; +import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.HMACAlgorithm; +import org.mozilla.jss.crypto.IVParameterSpec; +import org.mozilla.jss.crypto.IllegalBlockSizeException; import org.mozilla.jss.crypto.JSSMessageDigest; import org.mozilla.jss.crypto.SymmetricKey; +import org.mozilla.jss.crypto.TokenException; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; @@ -22,7 +33,18 @@ public class NistSP800_108KDF extends KDF { static final byte KDF_LABEL = 0x04; // arbitra - static final int SHA256_LENGTH = 32; + //SCP03, AES related constants + + public static final int SHA256_LENGTH = 32; + private static final int AES_CMAC_BLOCK_SIZE = 16; + private static final byte AES_CMAC_CONSTANT = (byte) 0x87; + public static final byte ENC_KDF_CONSTANT = (byte) 0x04; + public static final byte MAC_KDF_CONSTANT = (byte) 0x06; + public static final byte RMAC_KDF_CONSTANT = (byte) 0x07; + public static final byte CARD_CRYPTO_KDF_CONSTANT = 0x0; + public static final byte HOST_CRYPTO_KDF_CONSTANT = 0x1; + + SecureChannelProtocol protocol = null; @@ -57,7 +79,7 @@ public class NistSP800_108KDF extends KDF { String method = "NistSP800_108KDF.computeCardKeys:"; if (masterKey == null || context == null || token == null) { - throw new EBaseException(method + " Invlalid input parameters!"); + throw new EBaseException(method + " Invalid input parameters!"); } Map<String, SymmetricKey> keys = new HashMap<String, SymmetricKey>(); @@ -101,9 +123,9 @@ public class NistSP800_108KDF extends KDF { Arrays.fill(kek, (byte) 0); Arrays.fill(kdf_output, (byte) 0); - SymmetricKey macKey = protocol.unwrapSymKeyOnToken(token, null, macFinal, false); - SymmetricKey encKey = protocol.unwrapSymKeyOnToken(token, null, encFinal, false); - SymmetricKey kekKey = protocol.unwrapSymKeyOnToken(token, null, kekFinal, false); + SymmetricKey macKey = protocol.unwrapSymKeyOnToken(token, null, macFinal, false,SymmetricKey.DES3); + SymmetricKey encKey = protocol.unwrapSymKeyOnToken(token, null, encFinal, false,SymmetricKey.DES3); + SymmetricKey kekKey = protocol.unwrapSymKeyOnToken(token, null, kekFinal, false,SymmetricKey.DES3); Arrays.fill(encFinal, (byte) 0); Arrays.fill(macFinal, (byte) 0); @@ -117,6 +139,79 @@ public class NistSP800_108KDF extends KDF { } + //Compute the AES based CMAC operation. Used to derive session keys and cryptograms + public byte[] kdf_AES_CMAC_SCP03(SymmetricKey masterKey, byte[] context, byte kdfConstant, + int kdfOutputSizeBytes) throws EBaseException { + + String method = "NistSP800_108KDF.kdf_AES_CMAC_SCP03:"; + // 11 bytes label + byte[] label = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // sanity checking + + if (masterKey == null || context == null || kdfOutputSizeBytes <= 0) { + throw new EBaseException(method + " Invalid input!"); + } + + ByteArrayOutputStream data = new ByteArrayOutputStream(); + + int outputBits = kdfOutputSizeBytes * 8; + + //output size of cmac PRF + final int h = 128; + + int remainder = outputBits % h; + + //calculate counter size + int n = 0; + if (remainder == 0) { + n = outputBits / h; + } else { + n = outputBits / h + 1; + } + + byte b1 = (byte) ((outputBits >> 8) & 0xFF); + byte b2 = (byte) (outputBits & 0xFF); + + byte[] outputBitsBinary = new byte[2]; + outputBitsBinary[0] = b1; + outputBitsBinary[1] = b2; + + try { + data.write(label); + data.write(kdfConstant); + data.write(0x0); + data.write(outputBitsBinary); + } catch (IOException e) { + throw new EBaseException(method + "Unable to calculate kdf!"); + } + + byte[] headerBytes = data.toByteArray(); + + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ByteArrayOutputStream input = new ByteArrayOutputStream(); + + byte[] kI = null; + for (int i = 1; i <= n; i++) { + + try { + input.write(headerBytes); + input.write((byte) i); + input.write(context); + + kI = computeAES_CMAC(masterKey, input.toByteArray()); + + output.write(kI); + + } catch (IOException e) { + throw new EBaseException(method + "Unable to calculate kdf!"); + } + + } + + return output.toByteArray(); + } + /******************************************************************************* Key Derivation Function in Counter Mode using PRF = SHA256HMAC (NIST SP 800-108) Calculates 384 bits of diversified output from the provided master key (K_I) @@ -132,7 +227,6 @@ public class NistSP800_108KDF extends KDF { int L_BYTE_array_length = 2; // 384 = 0x0180 hex; 2 byte long representation if (context == null) { - throw new EBaseException(method + " Input value context must not be null."); } // sanity check that output buffer is large enough to contain 384 bits if (kdfOutputSizeBytes < KDF_OUTPUT_SIZE_BYTES) { @@ -215,4 +309,324 @@ public class NistSP800_108KDF extends KDF { return digestBytes; } + // Implements agorithm http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf + // Input an aes key of 128, 192, or 256 bits + // For now calling code only using 128 + // Will move later to common class used by both tks and tps + + public static byte[] computeAES_CMAC(SymmetricKey aesKey, byte[] input) throws EBaseException { + + String method = "NistSP800_108KDF.computeAES_CMAC:"; + byte iv[] = null; + + if (aesKey == null || input == null) { + throw new EBaseException(method + " invalid input data!"); + } + + byte[] data = new byte[input.length]; + System.arraycopy(input, 0, data, 0, input.length); + + String alg = aesKey.getAlgorithm(); + System.out.println(" AES ALG: " + alg); + + EncryptionAlgorithm eAlg = EncryptionAlgorithm.AES_128_CBC; + int ivLength = eAlg.getIVLength(); + + if (ivLength > 0) { + iv = new byte[ivLength]; + } + + if (!("AES".equals(alg))) { + throw new EBaseException(method + " invalid in put key type , must be AES!"); + } + + byte[] k0 = new byte[AES_CMAC_BLOCK_SIZE]; + + //Encrypt the zero array + CryptoToken token = aesKey.getOwningToken(); + Cipher encryptor = null; + + try { + encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + encryptor.initEncrypt(aesKey, new IVParameterSpec(iv)); + k0 = encryptor.doFinal(k0); + + } catch (NoSuchAlgorithmException | TokenException | IllegalStateException | IllegalBlockSizeException + | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new EBaseException(e); + } + + byte[] k1 = getAES_CMAC_SubKey(k0); + byte[] k2 = getAES_CMAC_SubKey(k1); + + int numBlocks = 0; + int messageSize = data.length;; + boolean perfectBlocks = false; + + if (((messageSize % AES_CMAC_BLOCK_SIZE) == 0) && (messageSize != 0)) { + numBlocks = messageSize / AES_CMAC_BLOCK_SIZE; + perfectBlocks = true; + } + else { + numBlocks = messageSize / AES_CMAC_BLOCK_SIZE + 1; + perfectBlocks = false; + } + + int index = 0; + byte inb = 0; + + byte[] finalData = null; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); + + if (perfectBlocks == true) + { + // If the size of the message is an integer multiple of the block block size (namely, 128 bits) (16 bytes) + // the last block shall be exclusive-OR'ed with the first subKey k1 + + for (int j = 0; j < k1.length; j++) { + index = messageSize - AES_CMAC_BLOCK_SIZE + j; + inb = data[index]; + data[index] = (byte) (inb ^ k1[j]); + } + try { + outputStream.write(data); + } catch (IOException e) { + throw new EBaseException(method + " internal buffer erro!"); + } + finalData = outputStream.toByteArray(); + } + else + { + // Otherwise, the last block shall be padded with 10^i + byte[] padding = new byte[AES_CMAC_BLOCK_SIZE - messageSize % AES_CMAC_BLOCK_SIZE]; + padding[0] = (byte) 0x80; + + try { + outputStream.write(data); + outputStream.write(padding); + } catch (IOException e) { + throw new EBaseException(method + " internal buffer error!"); + } + + finalData = outputStream.toByteArray(); + + //Get new data size , it's changed + messageSize = finalData.length; + + // and exclusive-OR'ed with K2 + for (int j = 0; j < k2.length; j++) { + index = messageSize - AES_CMAC_BLOCK_SIZE + j; + inb = finalData[index]; + finalData[index] = (byte) (inb ^ k2[j]); + } + } + + // Initialization vector starts as zeroes but changes inside the loop's + // subsequent iterations, it becomes the last encryption output + byte[] encData = new byte[AES_CMAC_BLOCK_SIZE]; + byte[] currentBlock = new byte[AES_CMAC_BLOCK_SIZE]; + for (int i = 0; i < numBlocks; i++) { + try { + encryptor.initEncrypt(aesKey, new IVParameterSpec(encData)); + System.arraycopy(finalData, i * AES_CMAC_BLOCK_SIZE, currentBlock, 0, AES_CMAC_BLOCK_SIZE); + encData = encryptor.doFinal(currentBlock); + } catch (TokenException | IllegalStateException | IllegalBlockSizeException + | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new EBaseException(e); + } + } + + return encData; + + } + + // SCP03 AES-CMAC support function + private static byte[] getAES_CMAC_SubKey(byte[] input) { + + byte[] output = new byte[input.length]; + + boolean msbSet = ((input[0]&0x80) != 0); + for (int i=0; i<input.length; i++) { + output[i] = (byte) (input[i] << 1); + if (i+1 < input.length && ((input[i+1]&0x80) != 0)) { + output[i] |= 0x01; + } + } + if (msbSet) { + output[output.length-1] ^= AES_CMAC_CONSTANT; + } + return output; + } + + // Collection of informal invocations of api used to create various session keys + // Done with test data. + public static void main(String[] args) { +/* + Options options = new Options(); + + options.addOption("d", true, "Directory for tokendb"); + + String db_dir = null; + CryptoManager cm = null; + + byte devKey[] = { (byte) 0x40, (byte) 0x41, (byte) 0x42, (byte) 0x43, (byte) 0x44, (byte) 0x45, (byte) 0x46, + (byte) 0x47, (byte) 0x48, (byte) 0x49, (byte) 0x4a, (byte) 0x4b, (byte) 0x4c, (byte) 0x4d, (byte) 0x4e, + (byte) 0x4f }; + + byte test_cuid[] = { (byte) 0x47,(byte) 0x90,(byte)0x50,(byte)0x37,(byte)0x72,(byte)0x71,(byte)0x97,(byte)0x00,(byte)0x74,(byte)0xA9 }; + byte test_kdd[] = { (byte)0x00, (byte)0x00, (byte)0x50, (byte)0x24,(byte) 0x97,(byte) 0x00,(byte) 0x74, (byte) 0xA9, (byte)0x72,(byte)0x71 }; + + + byte test_host_challenge[] = { 0x06 ,(byte)0xA4 ,0x46 ,0x57 ,(byte) 0x8B ,0x65 ,0x48 ,0x51 }; + byte test_card_challenge[] = { (byte) 0xAD ,(byte) 0x2E ,(byte)0xD0 ,0x1E ,0x7C ,0x2D ,0x0C ,0x6F}; + + byte test_key_info[] = { (byte) 0x02,(byte) 03,(byte) 00 }; + byte test_old_key_info[] = {0x01,0x03,0x00}; + + try { + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = parser.parse(options, args); + + if (cmd.hasOption("d")) { + db_dir = cmd.getOptionValue("d"); + } + + } catch (ParseException e) { + System.err.println("Error in parsing command line options: " + e.getMessage()); + + } + + SymmetricKey encKey = null; + SymmetricKey macKey = null; + SymmetricKey kekKey = null; + + SymmetricKey putEncKey = null; + SymmetricKey putMacKey = null; + SymmetricKey putKekKey = null; + + SymmetricKey tempKey = null; + + try { + CryptoManager.initialize(db_dir); + cm = CryptoManager.getInstance(); + + CryptoToken token = cm.getInternalKeyStorageToken(); + + KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.AES); + + SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4]; + usages[0] = SymmetricKey.Usage.WRAP; + usages[1] = SymmetricKey.Usage.UNWRAP; + usages[2] = SymmetricKey.Usage.ENCRYPT; + usages[3] = SymmetricKey.Usage.DECRYPT; + + kg.setKeyUsages(usages); + kg.temporaryKeys(true); + kg.initialize(128); + tempKey = kg.generate(); + + + Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + + int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + byte[] iv = null; + + if (ivLength > 0) { + iv = new byte[ivLength]; // all zeroes + } + + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey = encryptor.doFinal(devKey); + + KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap.initUnwrap(tempKey, new IVParameterSpec(iv)); + + encKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16); + macKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16); + kekKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 16); + + String transportName = "TPS-dhcp-16-206.sjc.redhat.com-8443 sharedSecret"; + SecureChannelProtocol prot = new SecureChannelProtocol(SecureChannelProtocol.PROTOCOL_THREE); + + SymmetricKey masterKey = SecureChannelProtocol.getSymKeyByName(token,"new_master"); + + GPParams params = new GPParams(); + params.setVersion1DiversificationScheme("visa2"); + params.setDiversificationScheme("visa2"); + + putEncKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info, + SecureChannelProtocol.encType, devKey, "defKeySet", test_cuid, test_kdd, null, null, + transportName,params); + + putMacKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info, + SecureChannelProtocol.macType, devKey, "defKeySet", test_cuid, test_kdd, null, null, + transportName,params); + + putKekKey = prot.computeSessionKey_SCP03("internal", "new_master",test_old_key_info, + SecureChannelProtocol.kekType, devKey, "defKeySet", test_cuid, test_kdd, null, null, + transportName,params); + + //create test session keys + encKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info, + SecureChannelProtocol.encType, devKey, "defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge, + transportName,params); + + macKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info, + SecureChannelProtocol.macType,devKey,"defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge, + transportName,params); + + kekKey = prot.computeSessionKey_SCP03("internal", "new_master",test_key_info, + SecureChannelProtocol.kekType, devKey, "defKeySet", test_cuid, test_kdd, test_host_challenge, test_card_challenge, + transportName,params); + + System.out.println("masterKey: " + masterKey); + + System.out.println("\n"); + + SecureChannelProtocol.debugByteArray(putEncKey.getKeyData(), " derived putEnc session key data: "); + SecureChannelProtocol.debugByteArray(putMacKey.getKeyData(), " derived putMac session key data: "); + SecureChannelProtocol.debugByteArray(putKekKey.getKeyData(), " derived putKek session key data: "); + + System.out.println("\n"); + + SecureChannelProtocol.debugByteArray(encKey.getKeyData(), " derived enc session key data: "); + SecureChannelProtocol.debugByteArray(macKey.getKeyData(), " derived mac session key data: "); + SecureChannelProtocol.debugByteArray(kekKey.getKeyData(), " derived kek session key data: "); + + ByteArrayOutputStream contextStream = new ByteArrayOutputStream(); + try { + contextStream.write(test_host_challenge); + contextStream.write(test_card_challenge); + } catch (IOException e) { + } + + StandardKDF standard = new StandardKDF(prot); + + ByteArrayOutputStream testContext = new ByteArrayOutputStream(); + + testContext.write(test_host_challenge); + testContext.write(test_card_challenge); + + NistSP800_108KDF nistKdf = new NistSP800_108KDF(prot); + + byte[] finalEncBytes = nistKdf.kdf_AES_CMAC_SCP03(encKey, testContext.toByteArray(), (byte) 0x04, 16); + byte[] finalMacBytes = nistKdf.kdf_AES_CMAC_SCP03(macKey, testContext.toByteArray(), (byte) 0x06, 16); + + SymmetricKey sEnc = prot.unwrapAESSymKeyOnToken(token, finalEncBytes, false); + SymmetricKey sMac = macKey = prot.unwrapAESSymKeyOnToken(token, finalMacBytes, false); + + byte[] cardCryptoVerify = nistKdf.kdf_AES_CMAC_SCP03(sMac, testContext.toByteArray(), CARD_CRYPTO_KDF_CONSTANT, 8); + SecureChannelProtocol.debugByteArray(cardCryptoVerify, " calculated card cryptogram"); + + byte[] hostCrypto = nistKdf.kdf_AES_CMAC_SCP03(sMac, testContext.toByteArray(), HOST_CRYPTO_KDF_CONSTANT, 8); + SecureChannelProtocol.debugByteArray(hostCrypto, " calculated host cryptogram"); + + } catch (AlreadyInitializedException e) { + // it is ok if it is already initialized + } catch (Exception e) { + System.err.println("JSS error!" + e); + System.exit(1); + } +*/ + } } diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java b/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java index 1766f0459..371e734df 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/SecureChannelProtocol.java @@ -15,6 +15,7 @@ import org.mozilla.jss.NoSuchTokenException; import org.mozilla.jss.crypto.Cipher; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; +import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; @@ -24,12 +25,12 @@ import org.mozilla.jss.crypto.SymmetricKey.NotExtractableException; import org.mozilla.jss.crypto.SymmetricKeyDeriver; import org.mozilla.jss.crypto.TokenException; +import sun.security.pkcs11.wrapper.PKCS11Constants; + import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.cmsutil.crypto.CryptoUtil; -import sun.security.pkcs11.wrapper.PKCS11Constants; - public class SecureChannelProtocol { static String sharedSecretKeyName = null; @@ -43,12 +44,14 @@ public class SecureChannelProtocol { static final int KEYNAMELENGTH = PREFIXLENGHT + 7; static final String TRANSPORT_KEY_NAME = "sharedSecret"; static final String DEFKEYSET_NAME = "defKeySet"; + static int protocol = 1; static final String encType = "enc"; static final String macType = "mac"; static final String kekType = "kek"; static final String authType = "auth"; static final String dekType = "dek"; + static final String rmacType = "rmac"; static final int PROTOCOL_ONE = 1; static final int PROTOCOL_TWO = 2; static final int PROTOCOL_THREE = 3; @@ -57,12 +60,26 @@ public class SecureChannelProtocol { //Size of long type in bytes, since java7 has no define for this static final int LONG_SIZE = 8; + // constants + + static final int AES_128_BYTES = 16; + static final int AES_192_BYTES = 24; + static final int AES_256_BYTES = 32; + + static final int AES_128_BITS = 128; + static final int AES_192_BITS = 192; + static final int AES_256_BITS = 256; + private SymmetricKey transportKey = null; CryptoManager cryptoManager = null; public SecureChannelProtocol() { } + public SecureChannelProtocol(int theProtocol) { + protocol = theProtocol; + } + public byte[] computeCryptogram_SCP01( String selectedToken, String keyNickName, byte[] card_challenge, byte[] host_challenge, byte[] keyInfo, @@ -144,6 +161,222 @@ public class SecureChannelProtocol { throw new EBaseException(method + " Not yet implemented!"); } + public int getProtocol() { + return protocol; + } + + // Either calculate a full session key, with the KDF applied or + // Merely calculate the card key. Card key mode is when host_challenge and + // card_challenge are passed in as null. Card keys are calculated + // when creating a new keyset to send to the token + public SymmetricKey computeSessionKey_SCP03(String selectedToken, + String keyNickName, byte[] keyInfo, String keyType, + byte[] devKeyArray, String keySet, byte[] xCUID, byte[] xKDD, + byte[] host_challenge, byte[] card_challenge, String transportKeyName, GPParams params) + throws EBaseException { + + final byte mac_constant = 0x06; + final byte enc_constant = 0x04; + final byte rmac_constant = 0x07; + + boolean noDerive = false; + + byte constant = 0; + + String method = "SecureChannelProtocol.computeSessionKey_SCP03:"; + + if (keyType == null || devKeyArray == null + || transportKeyName == null) { + throw new EBaseException(method + " invalid input data"); + } + + if (xCUID == null || xCUID.length <= 0) { + throw new EBaseException(method + "CUID invalid size!"); + } + + if (xKDD == null || xKDD.length != NistSP800_108KDF.KDD_SIZE_BYTES) { + throw new EBaseException(method + "KDD invalid size!"); + } + + + //Detect card key mode or full derivation mode + if (card_challenge == null && host_challenge == null) { + noDerive = true; + } else { + if (card_challenge == null || host_challenge == null) { + throw new EBaseException(method + " Invalid challenge data!"); + } + } + + CMS.debug(method + " entering. nickname: " + keyNickName + " selectedToken: " + selectedToken); + + CryptoManager cm = null; + CryptoToken token = null; + CryptoToken internalToken = null; + try { + cm = CryptoManager.getInstance(); + token = returnTokenByName(selectedToken, cm); + internalToken = returnTokenByName("internal", cm); + } catch (NotInitializedException e) { + CMS.debug(method + " " + e); + throw new EBaseException(e); + + } catch (NoSuchTokenException e) { + CMS.debug(method + " " + e); + throw new EBaseException(e); + } + + sharedSecretKeyName = SecureChannelProtocol.getSharedSecretKeyName(transportKeyName); + transportKey = getSharedSecretKey(internalToken); + + //concat host and card challenge: + + byte[] context = null; + + ByteArrayOutputStream contextStream = new ByteArrayOutputStream(); + + // Full derivation mode create context used in derivation + // host_challenge + card_challenge concatenated + if (noDerive == false) { + try { + contextStream.write(host_challenge); + contextStream.write(card_challenge); + } catch (IOException e) { + throw new EBaseException(method + " Error calculating derivation data!"); + } + + context = contextStream.toByteArray(); + } + + //Calculate the constant based on what type of key we want. + // Note the kek key never goes through final derivation in scp03 + + if (keyType.equalsIgnoreCase(SecureChannelProtocol.encType)) { + constant = enc_constant; + } + + if (keyType.equalsIgnoreCase(SecureChannelProtocol.macType)) { + constant = mac_constant; + } + + if (keyType.equalsIgnoreCase(SecureChannelProtocol.rmacType)) { + constant = rmac_constant; + } + + if (keyType.equalsIgnoreCase(SecureChannelProtocol.kekType)) { + constant = 0; + } + + String keyNameStr = null; + + SymmetricKey sessionKey = null; + SymmetricKey masterKey = null; + + if (keyNickName == null) { + keyNameStr = this.getKeyName(keyInfo); + } else { + keyNameStr = keyNickName; + } + + boolean noDivers = false; + + CMS.debug(method + " keyNameStr: " + keyNameStr); + + //Starting with version 1 or factory keyset. + if ((keyInfo[0] == 0x1 && keyNameStr.contains("#01#")) || + (keyInfo[0] == -1 && keyNameStr.indexOf("#FF") != -1)) + + { + String finalKeyType = keyType; + SymmetricKey devSymKey = returnDeveloperSymKey(token, finalKeyType, keySet, devKeyArray); + + StandardKDF standard = new StandardKDF(this); + SymmetricKey divKey = null; + + byte[] keyDiversified = null; + + //Consult the config to determine with diversification method to use. + if (params.isVer1DiversNone()) { + noDivers = true; + } else if (params.isVer1DiversEmv()) { + keyDiversified = KDF.getDiversificationData_EMV(xKDD, keyType); + } else if (params.isVer1DiversVisa2()) { + keyDiversified = KDF.getDiversificationData_VISA2(xKDD, keyType); + } else { + throw new EBaseException(method + " Invalid diversification method!"); + } + + //Obtain the card key,it may just be the raw developer key + if (noDivers == true) { + divKey = unwrapAESSymKeyOnToken(token, devKeyArray, false); + } else { + + // The g&d calls for computing the aes card key with DES, it will then be treated as aes + divKey = standard.computeCardKey_SCP03_WithDES3(devSymKey, keyDiversified, token); + } + + NistSP800_108KDF nistKdf = new NistSP800_108KDF(this); + + //IN scp03, the kek key IS the card key + if (constant == 0 /* kek key */) { + sessionKey = divKey; + } else { // session keys will become AES + if (noDerive) { + sessionKey = divKey; + } + else { + byte[] finalKeyBytes = nistKdf.kdf_AES_CMAC_SCP03(divKey, context, constant, 16); + sessionKey = unwrapAESSymKeyOnToken(token, finalKeyBytes, false); + + Arrays.fill(finalKeyBytes,(byte) 0); + + //The final session key is AES. + } + } + } else { // Creating a session key for the case where we have already upgraded the keys on the token, using the master key + CMS.debug(method + "In master key mode."); + + masterKey = getSymKeyByName(token, keyNameStr); + + StandardKDF standard = new StandardKDF(this); + + byte[] keyDiversified = null; + + if (params.isDiversNone()) { + throw new EBaseException(method + " No diversification requested in master key mode. Aborting..."); + } //Allow choice of emv or standard diversification + else if (params.isDiversEmv()) { + keyDiversified = KDF.getDiversificationData_EMV(xKDD, keyType); + } else if (params.isDiversVisa2()) { + keyDiversified = KDF.getDiversificationData_VISA2(xKDD, keyType); + } + + SymmetricKey divKey = null; + + divKey = standard.computeCardKey_SCP03_WithDES3(masterKey, keyDiversified, token); + + NistSP800_108KDF nistKdf = new NistSP800_108KDF(this); + // The kek session key does not call for derivation + if (constant == 0 /* kek key */) { + sessionKey = divKey; + } else { + if (noDerive) { + sessionKey = divKey; + } + else { + byte[] finalKeyBytes = nistKdf.kdf_AES_CMAC_SCP03(divKey, context, constant, 16); + sessionKey = unwrapAESSymKeyOnToken(token, finalKeyBytes, false); + + Arrays.fill(finalKeyBytes,(byte) 0); + } + } + } + + //SecureChannelProtocol.debugByteArray(sessionKey.getEncoded(), keyType + " : session key"); + + return sessionKey; + } + public SymmetricKey computeKEKKey_SCP01( String selectedToken, String keyNickName, byte[] keyInfo, @@ -153,7 +386,6 @@ public class SecureChannelProtocol { byte[] xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use byte[] devKeyArray, String useSoftToken_s, String keySet, String transportKeyName) throws EBaseException { - String method = "SecureChannelProtocol.computeKEKKey_SCP01:"; CMS.debug(method + " entering... "); @@ -294,7 +526,7 @@ public class SecureChannelProtocol { } else { StandardKDF standardKDF = new StandardKDF(this); CMS.debug(method + " ComputeSessionKey NistSP800_108KDF code: Using original KDF."); - byte[] data = KDF.getDiversificationData(context, keyType); + byte[] data = KDF.getDiversificationData_VISA2(context, keyType); devKey = standardKDF.computeCardKey(masterKey, data, token, PROTOCOL_ONE); } @@ -349,7 +581,7 @@ public class SecureChannelProtocol { byte[] parityEncrypted = KDF.getDesParity(encrypted); CMS.debug(method + "encryption completed"); - derivedKey = this.unwrapSymKeyOnToken(token, null, parityEncrypted, false); + derivedKey = this.unwrapSymKeyOnToken(token, null, parityEncrypted, false, SymmetricKey.DES3); } } catch (TokenException | InvalidKeyException | EBaseException e) { @@ -440,7 +672,7 @@ public class SecureChannelProtocol { From that point it is a simple matter of retrieving the desired key from the token. No security advantage is implied or desired here. */ - private SymmetricKey returnDeveloperSymKey(CryptoToken token, String keyType, String keySet, byte[] inputKeyArray) + public SymmetricKey returnDeveloperSymKey(CryptoToken token, String keyType, String keySet, byte[] inputKeyArray) throws EBaseException { SymmetricKey devKey = null; @@ -497,10 +729,157 @@ public class SecureChannelProtocol { return devKey; } - public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray, + //Takes raw des key 16 bytes, such as developer key and returns an AES key of the same size + //Supports 128 bits for now + public SymmetricKey unwrapAESSymKeyOnToken(CryptoToken token, byte[] inputKeyArray, + boolean isPerm) + throws EBaseException { + + String method = "SecureChannelProtocol.unwrapAESSymKeyOnToken:"; + CMS.debug(method + "Entering..."); + + if(token == null || inputKeyArray == null) { + throw new EBaseException(method + " Invalid input data!"); + } + + if(inputKeyArray.length < 16) { + throw new EBaseException(method + " Invalid key size!"); + } + + byte[] finalInputKeyArray = inputKeyArray; + if(inputKeyArray.length > 16) { + finalInputKeyArray = new byte[16]; + System.arraycopy(inputKeyArray, 0, finalInputKeyArray, 0, 16);; + + } + + KeyGenerator kg; + SymmetricKey finalAESKey; + try { + kg = token.getKeyGenerator(KeyGenAlgorithm.AES); + + SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4]; + usages[0] = SymmetricKey.Usage.WRAP; + usages[1] = SymmetricKey.Usage.UNWRAP; + usages[2] = SymmetricKey.Usage.ENCRYPT; + usages[3] = SymmetricKey.Usage.DECRYPT; + + kg.setKeyUsages(usages); + kg.temporaryKeys(true); + kg.initialize(128); + SymmetricKey tempKey = kg.generate(); + + //unwrap the test aes keys onto the token + + Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + + int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + byte[] iv = null; + + if (ivLength > 0) { + iv = new byte[ivLength]; // all zeroes + } + + encryptor.initEncrypt(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey = encryptor.doFinal(finalInputKeyArray); + + KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap.initUnwrap(tempKey, new IVParameterSpec(iv)); + finalAESKey = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.AES, 16); + + } catch (Exception e) { + throw new EBaseException(method + " Can't unwrap key onto token!"); + } + + return finalAESKey; + } + + //Supports 128 bits for now + //Used to convert a des key (on token) to aes + //Not used as of now, future if needed + public SymmetricKey unwrapAESSymKeyOnToken(CryptoToken token, SymmetricKey keyToUnwrap, boolean isPerm) throws EBaseException { + String method = "SecureChannelProtocol.unwrapAESSymKeyOnToken:"; + CMS.debug(method + "Entering..."); + + if(token == null || keyToUnwrap == null) { + throw new EBaseException(method + " Invalid input data!"); + } + + if(keyToUnwrap.getLength()< 16) { + throw new EBaseException(method + " Invalid key size!"); + } + + KeyGenerator kg; + SymmetricKey finalAESKey; + try { + kg = token.getKeyGenerator(KeyGenAlgorithm.AES); + + SymmetricKey.Usage usages[] = new SymmetricKey.Usage[4]; + usages[0] = SymmetricKey.Usage.WRAP; + usages[1] = SymmetricKey.Usage.UNWRAP; + usages[2] = SymmetricKey.Usage.ENCRYPT; + usages[3] = SymmetricKey.Usage.DECRYPT; + + kg.setKeyUsages(usages); + kg.temporaryKeys(true); + kg.initialize(128); + SymmetricKey tempKey = kg.generate(); + + + int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + byte[] iv = null; + + if (ivLength > 0) { + iv = new byte[ivLength]; // all zeroes + } + + //Wrap the arbitrary key first + + int len = keyToUnwrap.getLength(); + + SymmetricKey finalKeyToWrap = null; + SymmetricKey key16 = null; + if(len > 16) { + key16 = extractDes2FromDes3(keyToUnwrap, token.getName()); + if(key16 != null) + len = key16.getLength(); + finalKeyToWrap = key16; + } else { + finalKeyToWrap = keyToUnwrap; + } + + KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap.initWrap(tempKey, new IVParameterSpec(iv)); + byte[] wrappedKey = keyWrap.wrap(finalKeyToWrap); + + //Now unwrap to an AES key + + KeyWrapper keyUnWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyUnWrap.initUnwrap(tempKey, new IVParameterSpec(iv)); + finalAESKey = keyUnWrap.unwrapSymmetric(wrappedKey, SymmetricKey.AES, 16); + + + Arrays.fill(wrappedKey,(byte) 0); + + //byte[] finalKeyBytes = finalAESKey.getKeyData(); + //displayByteArray(finalKeyBytes, false); + + } catch (Exception e) { + throw new EBaseException(method + " Can't unwrap key onto token!"); + } + + return finalAESKey; + + } + + //Final param allows us to request the final type, DES or AES + public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray, + boolean isPerm, SymmetricKey.Type finalKeyType) + throws EBaseException { + String method = "SecureChannelProtocol.unwrapSymKeyOnToken:"; CMS.debug(method + "Entering..."); SymmetricKey unwrapped = null; @@ -535,7 +914,7 @@ public class SecureChannelProtocol { byte[] finalKeyArray = null; - if (inputKeyArray.length == DES2_LENGTH) { + if (inputKeyArray.length == DES2_LENGTH && finalKeyType == SymmetricKey.DES3) { finalKeyArray = SecureChannelProtocol.makeDes3FromDes2(inputKeyArray); } @@ -570,9 +949,9 @@ public class SecureChannelProtocol { if (isPerm == true) { unwrapped = keyWrap.unwrapSymmetricPerm(wrappedKey, - SymmetricKey.DES3, 0); + finalKeyType, 0); } else { - unwrapped = keyWrap.unwrapSymmetric(wrappedKey, SymmetricKey.DES3, 0); + unwrapped = keyWrap.unwrapSymmetric(wrappedKey, finalKeyType, 0); } } catch (Exception e) { @@ -590,8 +969,9 @@ public class SecureChannelProtocol { return unwrapped; } + //Final param allows us to request the final type, DES or AES public SymmetricKey unwrapWrappedSymKeyOnToken(CryptoToken token, SymmetricKey unwrappingKey, byte[] inputKeyArray, - boolean isPerm) + boolean isPerm, SymmetricKey.Type keyType) throws EBaseException { String method = "SecureChannelProtocol.unwrapWrappedSymKeyOnToken:"; @@ -613,13 +993,15 @@ public class SecureChannelProtocol { if (isPerm) { unwrapped = keyWrap.unwrapSymmetricPerm(inputKeyArray, - SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, inputKeyArray.length); + keyType, SymmetricKey.Usage.UNWRAP, inputKeyArray.length); } else { - unwrapped = keyWrap.unwrapSymmetric(inputKeyArray, SymmetricKey.DES3, SymmetricKey.Usage.UNWRAP, + unwrapped = keyWrap.unwrapSymmetric(inputKeyArray, keyType, SymmetricKey.Usage.UNWRAP, inputKeyArray.length); } - finalUnwrapped = makeDes3KeyDerivedFromDes2(unwrapped, token.getName()); + if (keyType == SymmetricKey.DES3) { + finalUnwrapped = makeDes3KeyDerivedFromDes2(unwrapped, token.getName()); + } } catch (Exception e) { CMS.debug(method + " " + e); @@ -629,7 +1011,10 @@ public class SecureChannelProtocol { //CMS.debug(method + "Returning symkey: " + unwrapped); CMS.debug(method + "Returning symkey..."); - return finalUnwrapped; + if (finalUnwrapped != null) + return finalUnwrapped; + else + return unwrapped; } public SymmetricKey unwrapSymKeyOnToken(CryptoToken token, byte[] inputKeyArray, boolean isPerm) @@ -648,7 +1033,7 @@ public class SecureChannelProtocol { } SymmetricKey transport = getSharedSecretKey(token); - unwrapped = this.unwrapSymKeyOnToken(token, transport, inputKeyArray, isPerm); + unwrapped = this.unwrapSymKeyOnToken(token, transport, inputKeyArray, isPerm, SymmetricKey.DES3); CMS.debug(method + "Returning symkey: " + unwrapped); @@ -710,16 +1095,36 @@ public class SecureChannelProtocol { public static void debugByteArray(byte[] array, String message) { CMS.debug("About to dump array: " + message); + System.out.println("About to dump array: " + message); if (array == null) { CMS.debug("Array to dump is empty!"); return; } + System.out.println("################### "); CMS.debug("################### "); String result = getHexString(array); CMS.debug(result); + System.out.println(result); + } + + public static void + displayByteArray(byte[] ba, boolean has_check_sum) { + char mask = 0xff; + + if (has_check_sum == true) + mask = 0xfe; + + for (int i = 0; i < ba.length; i++) { + + System.out.print(Integer.toHexString(ba[i] & mask) + " "); + if ((i % 26) == 25) { + System.out.println(""); + } + } + System.out.println(""); } final protected static char[] hex = "0123456789abcdef".toCharArray(); @@ -815,6 +1220,8 @@ public class SecureChannelProtocol { } SymmetricKey des2 = this.extractDes2FromDes3(symKey, devKeyToken); + //SecureChannelProtocol.debugByteArray(des2.getEncoded(), method + " raw des2 key, to be wrapped."); + result = this.wrapSessionKey(selectedToken, des2, devKey); // SecureChannelProtocol.debugByteArray(result, " Wrapped des2 key"); @@ -929,25 +1336,93 @@ public class SecureChannelProtocol { wrapper = wrappingKey; } - try { - CryptoManager cm = this.getCryptoManger(); - CryptoToken token = returnTokenByName(tokenName, cm); + CMS.debug(method + " wrapper key type: " + wrapper.getType()); - keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.DES3_ECB); - keyWrap.initWrap(wrapper, null); - wrappedSessKeyData = keyWrap.wrap(sessionKey); - } catch (Exception e) { - CMS.debug(method + " " + e); - throw new EBaseException(e); + if (wrapper.getType() != SymmetricKey.AES) { + CMS.debug(method + "Trying to wrap a key with an DES key!"); + + try { + CryptoManager cm = this.getCryptoManger(); + CryptoToken token = returnTokenByName(tokenName, cm); + + keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.DES3_ECB); + keyWrap.initWrap(wrapper, null); + wrappedSessKeyData = keyWrap.wrap(sessionKey); + + } catch ( + Exception e) { + CMS.debug(method + " " + e); + throw new EBaseException(e); + } + + } else if (wrapper.getType() == SymmetricKey.AES) { + CMS.debug(method + "Trying to wrap a key with an AES key!"); + try { + CryptoManager cm = this.getCryptoManger(); + CryptoToken token = returnTokenByName(tokenName, cm); + + int ivLength = EncryptionAlgorithm.AES_128_CBC.getIVLength(); + byte[] iv = null; + + if (ivLength > 0) { + iv = new byte[ivLength]; // all zeroes + } + + keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.AES_CBC); + keyWrap.initWrap(wrapper, new IVParameterSpec(iv)); + wrappedSessKeyData = keyWrap.wrap(sessionKey); + + + } catch (Exception e) { + CMS.debug(method + " " + e); + throw new EBaseException(e); + } } - //CMS.debug(method + " About to return session key: " + wrappedSessKeyData); + + //SecureChannelProtocol.debugByteArray(wrappedSessKeyData, "wrappedSessKeyData"); CMS.debug(method + " returning session key"); return wrappedSessKeyData; } + //128 for now. + public byte[] computeAES_CBCEncryption(SymmetricKey symKey, String selectedToken, byte[] input, byte[] iv) + throws EBaseException + { + String method = "SecureChannelProtocol.computeAES_CBCEncryption"; + byte[] output = null; + byte[] finalIv = null; + + if (symKey == null || selectedToken == null) { + throw new EBaseException(method + " Invalid input data."); + } + + if (iv == null) { + finalIv = new byte[16]; + + } else { + finalIv = iv; + } + + try { + CryptoManager cm = this.getCryptoManger(); + CryptoToken token = returnTokenByName(selectedToken, cm); + Cipher encryptor = token.getCipherContext(EncryptionAlgorithm.AES_128_CBC); + encryptor.initEncrypt(symKey, new IVParameterSpec(finalIv)); + output = encryptor.doFinal(input); + + SecureChannelProtocol.debugByteArray(output, "Encrypted data:"); + } catch (Exception e) { + + CMS.debug(method + e); + throw new EBaseException(method + e); + } + + return output; + } + public byte[] computeDes3EcbEncryption(SymmetricKey desKey, String selectedToken, byte[] input) throws EBaseException { @@ -983,6 +1458,61 @@ public class SecureChannelProtocol { return output; } + //SCP03 uses aes + public byte[] computeKeyCheck_SCP03(SymmetricKey symKey, String selectedToken) throws EBaseException { + + String method = "SecureChannelProtocol.computeKeyCheck_SCP03:"; + + if (symKey == null || selectedToken == null) { + throw new EBaseException(method + " invalid input data!"); + } + + byte[] key_check_message = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + //zero iv vector + byte[] key_check_iv = new byte[16]; + + byte[] output = null; + byte[] finalOutput = new byte[3]; + + try { + output = computeAES_CBCEncryption(symKey, selectedToken, key_check_message, key_check_iv); + } catch (EBaseException e) { + CMS.debug(method + e); + throw e; + + } + + //Get the 3 bytes needed + System.arraycopy(output, 0, finalOutput, 0, 3); + + //SecureChannelProtocol.debugByteArray(finalOutput, method + " output: "); + + return finalOutput; + } + + //AES, uses AES_CMAC alg to do the work. + public byte[] computeCryptogram_SCP03(SymmetricKey symKey, String selectedToken, byte[] context, byte cryptoType) + throws EBaseException { + String method = "SecureChannelProtocol.computeCryptogram_"; + + CMS.debug(method + " entering .."); + + if (symKey == null || selectedToken == null || (cryptoType != NistSP800_108KDF.CARD_CRYPTO_KDF_CONSTANT) + && cryptoType != NistSP800_108KDF.HOST_CRYPTO_KDF_CONSTANT) { + throw new EBaseException(method + " Invalid input data."); + } + + NistSP800_108KDF nistKdf = new NistSP800_108KDF(this); + byte[] crypto = nistKdf.kdf_AES_CMAC_SCP03(symKey, context, cryptoType, 8); + //SecureChannelProtocol.debugByteArray(crypto, " calculated cryptogram"); + + byte[] finalCrypto = new byte[8]; + + System.arraycopy(crypto, 0, finalCrypto, 0, 8); + + return finalCrypto; + } + public byte[] computeKeyCheck(SymmetricKey desKey, String selectedToken) throws EBaseException { String method = "SecureChannelProtocol.computeKeyCheck:"; @@ -1115,6 +1645,9 @@ public class SecureChannelProtocol { return output; } + //Calculates the 3 new card keys to be written to the token for + //Symmetric key changeover. Supports SCP03 now. + //Provide all the static developer key arrays should we need them public byte[] diversifyKey(String tokenName, String newTokenName, String oldMasterKeyName, @@ -1125,12 +1658,18 @@ public class SecureChannelProtocol { boolean nistSP800_108KdfUseCuidAsKdd, byte[] CUIDValue, byte[] KDD, - byte[] kekKeyArray, - String useSoftToken, String keySet, byte protocol) throws EBaseException { + byte[] kekKeyArray, byte[] encKeyArray, byte[] macKeyArray, + String useSoftToken, String keySet, byte protocol, GPParams params) throws EBaseException { String method = "SecureChannelProtocol.diversifyKey:"; - CMS.debug(method + " Entering ... newTokenName: " + newTokenName); + CMS.debug(method + " Entering ... newTokenName: " + newTokenName + " protocol: " + protocol); + CMS.debug(method + " oldMasterKeyName: " + oldMasterKeyName); + CMS.debug(method + " newMasterKeyName: " + newMasterKeyName); + + SecureChannelProtocol.debugByteArray(encKeyArray, " Developer enc key array: "); + SecureChannelProtocol.debugByteArray(macKeyArray, " Developer mac key array: "); + SecureChannelProtocol.debugByteArray(kekKeyArray, " Developer kek key array: "); SymmetricKey masterKey = null; SymmetricKey oldMasterKey = null; @@ -1151,7 +1690,7 @@ public class SecureChannelProtocol { byte[] output = null; if (oldMasterKeyName == null || oldKeyInfo == null || newKeyInfo == null - || keySet == null) { + || keySet == null || params == null) { throw new EBaseException(method + "Invalid input!"); } @@ -1162,6 +1701,9 @@ public class SecureChannelProtocol { String fullNewMasterKeyName = getFullMasterKeyName(newMasterKeyName); String fullOldMasterKeyName = getFullMasterKeyName(oldMasterKeyName); + CMS.debug(method + " fullOldMasterKeyName: " + fullOldMasterKeyName); + CMS.debug(method + " fullNewMasterKeyName: " + fullNewMasterKeyName); + CryptoManager cm = null; CryptoToken token = null; CryptoToken newToken = null; @@ -1217,16 +1759,27 @@ public class SecureChannelProtocol { StandardKDF standardKDF = new StandardKDF(this); NistSP800_108KDF nistKDF = new NistSP800_108KDF(this); - KDCenc = KDF.getDiversificationData(KDD, SecureChannelProtocol.encType); - KDCmac = KDF.getDiversificationData(KDD, SecureChannelProtocol.macType); - KDCkek = KDF.getDiversificationData(KDD, SecureChannelProtocol.kekType); + KDCenc = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.encType); + KDCmac = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.macType); + KDCkek = KDF.getDiversificationData_VISA2(KDD, SecureChannelProtocol.kekType); - if (protocol == PROTOCOL_ONE) { - if (checkForDeveloperKeySet(oldMasterKeyName) == true) { - CMS.debug(method + " Developer key set case: "); - } else { - CMS.debug(method + " Not Developer key set case: "); + //This routine does not even support protocol 2, bail if asked to do so. + if (protocol == PROTOCOL_TWO) { + throw new EBaseException(method + " SCP 02 not yet supported here."); + } + String transportKeyName = SecureChannelProtocol.getSharedSecretKeyName(null); + + if (checkForDeveloperKeySet(oldMasterKeyName) == true) { + //Starting with the deve key set, do nothing in this clause + CMS.debug(method + " Developer key set case: protocol: " + protocol); + } else { + //Case where down grading back to the deve key set, or to another master key set + // This clause does nothing but calculate the kek key of the + // Current keyset, which will be used to wrap the new keys, to be calculated + CMS.debug(method + " Not Developer key set case: "); + + if (protocol == PROTOCOL_ONE ) { if (NistSP800_108KDF.useThisKDF(nistSP800_108KdfOnKeyVersion, oldKeyVersion)) { CMS.debug(method + " NistSP800_108KDF code: Using NIST SP800-108 KDF."); @@ -1252,19 +1805,44 @@ public class SecureChannelProtocol { old_kek_sym_key = standardKDF.computeCardKey(oldMasterKey, KDCkek, token, PROTOCOL_ONE); } - } + } else { // Protocol 3 - /* special case #01#01 */ - if (fullNewMasterKeyName != null && fullNewMasterKeyName.equals("#01#01")) - { - CMS.debug(method + " Special case dev key set for DiversifyKey!"); + old_kek_sym_key = this.computeSessionKey_SCP03(tokenName, oldMasterKeyName, + oldKeyInfo, SecureChannelProtocol.kekType, kekKeyArray, keySet, + CUIDValue, KDD, null, null, transportKeyName, params); + CMS.debug(method + " Moving back to the developer key set case, protocol 3"); + } + } + + // Now compute the new keys to be written to the token. + /* special case #01#01 */ + if (fullNewMasterKeyName != null + && (fullNewMasterKeyName.equals("#01#01") || fullNewMasterKeyName.contains("#01#03"))) + { + //This is the case where we revert to the original developer key set or key set 1 + if (protocol == PROTOCOL_ONE) { + CMS.debug(method + " Special case returning to the dev key set (1) for DiversifyKey, protocol 1!"); encKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.encType, keySet, null); macKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.macType, keySet, null); kekKey = returnDeveloperSymKey(newToken, SecureChannelProtocol.kekType, keySet, null); - } else { - CMS.debug(method + " Compute card key on token case ! For new key version"); + } else if (protocol == PROTOCOL_THREE) { + CMS.debug(method + " Special case or returning to the dev key set (or ver 1) for DiversifyKey, protocol 3!"); + encKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo, + SecureChannelProtocol.encType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + macKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo, + SecureChannelProtocol.macType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + kekKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, newKeyInfo, + SecureChannelProtocol.kekType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + } + } else { + //Compute new card keys for upgraded key set + CMS.debug(method + " Compute card key on token case ! For new key version."); + if (protocol == PROTOCOL_ONE) { if (NistSP800_108KDF.useThisKDF(nistSP800_108KdfOnKeyVersion, newKeyVersion)) { CMS.debug(method + " NistSP800_108KDF code: Using NIST SP800-108 KDF. For new key version."); @@ -1289,17 +1867,31 @@ public class SecureChannelProtocol { kekKey = standardKDF.computeCardKeyOnToken(masterKey, KDCkek, protocol); } - if (encKey == null || macKey == null || kekKey == null) { - throw new EBaseException(method - + " Can't derive session keys with selected KDF. For new key version."); - } + } else { // protocol 3 + CMS.debug(method + " Generating new card keys to upgrade to, protocol 3."); + encKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo, + SecureChannelProtocol.encType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + macKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo, + SecureChannelProtocol.macType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + kekKey = this.computeSessionKey_SCP03(tokenName, newMasterKeyName, oldKeyInfo, + SecureChannelProtocol.kekType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + + // Generate an old kek key to do the encrypting of the new static keys + + old_kek_sym_key = this.computeSessionKey_SCP03(tokenName, oldMasterKeyName, oldKeyInfo, + SecureChannelProtocol.kekType, kekKeyArray, + keySet, CUIDValue, KDD, null, null, transportKeyName, params); + } + + if (encKey == null || macKey == null || kekKey == null) { + throw new EBaseException(method + + " Can't derive session keys with selected KDF. For new key version."); } - } else if (protocol == PROTOCOL_TWO) { - throw new EBaseException(method + " SCP 02 not yet supported here."); - } else { - throw new EBaseException(method + " Unsupported protocol verison."); } boolean showKeysForDebug = false; @@ -1327,7 +1919,9 @@ public class SecureChannelProtocol { } else { CMS.debug(method + " old kek sym key is null"); + old_kek_sym_key = returnDeveloperSymKey(token, SecureChannelProtocol.kekType, keySet, kekKeyArray); + output = createKeySetDataWithSymKeys(newKeyVersion, (byte[]) null, old_kek_sym_key, encKey, @@ -1340,6 +1934,8 @@ public class SecureChannelProtocol { return output; } + //Create the actual blob of new keys to be written to the token + // Suports prot1 and prot3 private byte[] createKeySetDataWithSymKeys(byte newKeyVersion, byte[] old_kek_key_array, SymmetricKey old_kek_sym_key, SymmetricKey encKey, SymmetricKey macKey, SymmetricKey kekKey, byte protocol, String tokenName) @@ -1392,6 +1988,8 @@ public class SecureChannelProtocol { wrappingKey = old_kek_sym_key; } + CMS.debug(method + "Wrapping key: length: " + wrappingKey.getLength()); + alg = (byte) 0x81; encKey16 = extractDes2FromDes3(encKey, tokenName); macKey16 = extractDes2FromDes3(macKey, tokenName); @@ -1404,23 +2002,48 @@ public class SecureChannelProtocol { keycheck_enc_key = this.computeKeyCheck(encKey, tokenName); keycheck_mac_key = this.computeKeyCheck(macKey, tokenName); keycheck_kek_key = this.computeKeyCheck(kekKey, tokenName); - /* - debugByteArray(keycheck_enc_key, " Keycheck enc key: "); - debugByteArray(keycheck_mac_key, " Keycheck mac key: "); - debugByteArray(keycheck_kek_key, " KeyCheck kek key: "); - */ } else if (protocol == PROTOCOL_TWO) { - alg = (byte) 0x80; throw new EBaseException(method + " SCP 02 not yet implemented!"); + } else if (protocol == PROTOCOL_THREE) { + CMS.debug(method + " Attempting SCP03"); + + if (old_kek_sym_key == null) { + CMS.debug(method + " SCP03: Using old kek key array."); + wrappingKey = unwrapAESSymKeyOnToken(token, old_kek_key_array, false); + } else { + CMS.debug(method + "SCP03: Using input old key key sym key."); + wrappingKey = old_kek_sym_key; + } + + alg = (byte) 0x88; + + encrypted_enc_key = this.wrapSessionKey(tokenName, encKey, wrappingKey); + encrypted_mac_key = this.wrapSessionKey(tokenName, macKey, wrappingKey); + encrypted_kek_key = this.wrapSessionKey(tokenName, kekKey, wrappingKey); + + keycheck_enc_key = this.computeKeyCheck_SCP03(encKey, tokenName); + keycheck_mac_key = this.computeKeyCheck_SCP03(macKey, tokenName); + keycheck_kek_key = this.computeKeyCheck_SCP03(kekKey, tokenName); + } else { throw new EBaseException(method + " Invalid SCP version requested!"); } // Compose the final key set data byte array - byte[] b1 = new byte[] { alg, 0x10 }; - byte[] b2 = new byte[] { 0x3 }; + byte[] b1 = null; + byte[] b2 = null; + + if (protocol == PROTOCOL_THREE) { + //Will be different if the key is bigger than AES 128 + // Support 128 for now + b1 = new byte[] { alg, 0x11, (byte) encrypted_enc_key.length }; + } else { + b1 = new byte[] { alg, 0x10 }; + } + + b2 = new byte[] { 0x3 }; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -1484,6 +2107,10 @@ public class SecureChannelProtocol { if (keyInfo.equals("#01#02") || keyInfo.equals("#FF#02")) return true; + //SCP03 + if (keyInfo.contains("#01#03") || keyInfo.contains("#FF#03")) + return true; + return false; } @@ -1493,6 +2120,42 @@ public class SecureChannelProtocol { } } + + //SCP03 wrap a session key with AES kek key. + public byte[] encryptData_SCP03(String selectedToken, String keyNickName, byte[] data, byte[] keyInfo, + byte nistSP800_108KdfOnKeyVersion, boolean nistSP800_108KdfUseCuidAsKdd, byte[] xCUID, byte[] xKDD, + byte[] kekKeyArray, String useSoftToken_s, String keySet, GPParams params) throws EBaseException { + + String method = "SecureChannelProtocol.encryptData_SCP03:"; + + CMS.debug(method + " Entering ...."); + + String transportKeyName = SecureChannelProtocol.getSharedSecretKeyName(null); + + if (keyInfo == null || keySet == null || (keyInfo == null || keyInfo.length < 2) || params == null) { + throw new EBaseException(method + "Invalid input!"); + } + + if (xCUID == null || xCUID.length <= 0) { + throw new EBaseException(method + "CUID invalid size!"); + } + + if (xKDD == null || xKDD.length != NistSP800_108KDF.KDD_SIZE_BYTES) { + throw new EBaseException(method + "KDD invalid size!"); + } + + SymmetricKey kekKey = computeSessionKey_SCP03(selectedToken, keyNickName, + keyInfo, kekType, kekKeyArray, keySet, xCUID, xKDD, + null, null, transportKeyName, params); + + byte[] output = null; + output = computeAES_CBCEncryption(kekKey, selectedToken, data, null); + + debugByteArray(output, method + " encryptData: Output: "); + + return output; + } + public byte[] encryptData(String selectedToken, String keyNickName, byte[] data, byte[] keyInfo, byte nistSP800_108KdfOnKeyVersion, boolean nistSP800_108KdfUseCuidAsKdd, byte[] xCUID, byte[] xKDD, byte[] kekKeyArray, String useSoftToken_s, String keySet) throws EBaseException { diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java b/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java index 1d61a465d..8c228a15c 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/StandardKDF.java @@ -19,6 +19,39 @@ public class StandardKDF extends KDF { this.protocol = protocol; } + // For the scp03 g&d smart cafe, the dev keys must start out as DES3 keys + // but then this routine must return the AES version of the key + + public SymmetricKey computeCardKey_SCP03_WithDES3(SymmetricKey masterKey, byte[] derivationData, CryptoToken token) + throws EBaseException { + + String method = "StandardKDF.computeCardKey_SCP03_WithDES3:"; + + CMS.debug(method + " entering ..."); + + if (masterKey == null || token == null + || derivationData == null || ((derivationData.length != SecureChannelProtocol.AES_128_BYTES) && + (derivationData.length != SecureChannelProtocol.AES_192_BYTES) && + (derivationData.length != SecureChannelProtocol.AES_256_BYTES))) { + + CMS.debug(method + " Invalid input parameters!"); + + throw new EBaseException(method + " Invalid input parameters!"); + } + + //Now the new key data is the derivation data encrypted with DESS3 + + byte[] encrypted; + try { + encrypted = this.protocol.computeDes3EcbEncryption(masterKey, token.getName(), derivationData); + } catch (TokenException e) { + throw new EBaseException(method + "Can't derive key data!"); + } + //SecureChannelProtocol.debugByteArray(encrypted, "calculated key: "); + + return this.protocol.unwrapAESSymKeyOnToken(token, encrypted, false); + + } public SymmetricKey computeCardKey(SymmetricKey masterKey, byte[] derivationData, CryptoToken token, int protocol) throws EBaseException { @@ -54,12 +87,14 @@ public class StandardKDF extends KDF { CMS.debug(method + "Now try this the old fashioned way"); byte[] encrypted = this.protocol.computeDes3EcbEncryption(masterKey, token.getName(), derivationData); - byte[] parityEncrypted = KDF.getDesParity(encrypted); + SecureChannelProtocol.debugByteArray(encrypted, "calculated key: "); + // byte[] parityEncrypted = KDF.getDesParity(encrypted); CMS.debug(method + "done computeDes3EcbEncryptiong"); + derivedKey = this.protocol.unwrapSymKeyOnToken(token, null, - parityEncrypted, false); + encrypted, false,SymmetricKey.DES3); - // The key this way is aleady des3, return + // The key this way is already final, return return derivedKey; } diff --git a/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java b/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java index a282cd26f..6a1746616 100644 --- a/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java +++ b/base/server/cms/src/com/netscape/cms/servlet/tks/TokenServlet.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.OutputStream; import java.security.PublicKey; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.StringTokenizer; import javax.servlet.ServletConfig; @@ -1570,8 +1571,11 @@ public class TokenServlet extends CMSServlet { return cs.getString("tks.tksSharedSymKeyName", TRANSPORT_KEY_NAME); } + //Accepts protocol param and supports scp03. private void processDiversifyKey(HttpServletRequest req, HttpServletResponse resp) throws EBaseException { + + String method = "TokenServlet.processDiversifyKey: "; byte[] KeySetData, xCUID, xKDD; // AC: KDF SPEC CHANGE: removed duplicative 'CUID' variable and added xKDD // AC: BUGFIX: Record the actual parameters to DiversifyKey in the audit log. @@ -1609,6 +1613,9 @@ public class TokenServlet extends CMSServlet { String rProtocol = req.getParameter(IRemoteRequest.CHANNEL_PROTOCOL); String rWrappedDekKey = req.getParameter(IRemoteRequest.WRAPPED_DEK_SESSION_KEY); + + CMS.debug(method + "rWrappedDekKey: " + rWrappedDekKey); + int protocol = 1; String auditMessage = ""; @@ -1670,13 +1677,13 @@ public class TokenServlet extends CMSServlet { if (!missingParam) { xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(oldMasterKeyName); - if (xkeyInfo == null || xkeyInfo.length != 2) { + if (xkeyInfo == null || (xkeyInfo.length != 2 && xkeyInfo.length != 3)) { badParams += " KeyInfo length,"; CMS.debug("TokenServlet: Invalid key info length"); missingParam = true; } xnewkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(newMasterKeyName); - if (xnewkeyInfo == null || xnewkeyInfo.length != 2) { + if (xnewkeyInfo == null || (xnewkeyInfo.length != 2 && xnewkeyInfo.length != 3)) { badParams += " NewKeyInfo length,"; CMS.debug("TokenServlet: Invalid new key info length"); missingParam = true; @@ -1692,7 +1699,6 @@ public class TokenServlet extends CMSServlet { CMS.debug("process DiversifyKey: protocol value: " + protocol); if (protocol == 2) { - if ((rWrappedDekKey == null) || (rWrappedDekKey.equals(""))) { badParams += " WrappedDekKey,"; CMS.debug("TokenServlet: processDiversifyKey(): missing request parameter: WrappedDekKey, with SCP02."); @@ -1766,7 +1772,12 @@ public class TokenServlet extends CMSServlet { if (mNewKeyNickName != null) newMasterKeyName = mNewKeyNickName; - String oldKeyInfoMap = "tks." + keySet + ".mk_mappings." + req.getParameter(IRemoteRequest.TOKEN_KEYINFO); //#xx#xx + String tokKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO); + + // Get the first 6 characters, since scp03 gives us extra characters. + tokKeyInfo = tokKeyInfo.substring(0,6); + String oldKeyInfoMap = "tks." + keySet + ".mk_mappings." + tokKeyInfo; //#xx#xx + CMS.debug(method + " oldKeyInfoMap: " + oldKeyInfoMap); String oldMappingValue = CMS.getConfigStore().getString(oldKeyInfoMap, null); String oldSelectedToken = null; if (oldMappingValue == null) { @@ -1778,7 +1789,9 @@ public class TokenServlet extends CMSServlet { oldKeyNickName = st.nextToken(); } - String newKeyInfoMap = "tks.mk_mappings." + rnewKeyInfo; //#xx#xx + + String newKeyInfoMap = "tks.mk_mappings." + rnewKeyInfo.substring(0,6); //#xx#xx + CMS.debug(method + " newKeyInfoMap: " + newKeyInfoMap); String newMappingValue = CMS.getConfigStore().getString(newKeyInfoMap, null); String newSelectedToken = null; if (newMappingValue == null) { @@ -1795,14 +1808,22 @@ public class TokenServlet extends CMSServlet { " oldKeyNickName=" + oldKeyNickName + " newKeyNickName=" + newKeyNickName); - byte kekKeyArray[] = - com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key")); + byte kekKeyArray[] = getDeveKeyArray("kek_key", sconfig, keySet); + byte macKeyArray[] = getDeveKeyArray("auth_key", sconfig, keySet); + byte encKeyArray[] = getDeveKeyArray("mac_key", sconfig, keySet); + + // com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key")); + + //GPParams for scp03 right now, reads some scp03 specific values from the config of a given keyset + // passed down to the SecureChannelProtocol functions that deal with SCP03 + + GPParams gp3Params = readGPSettings(keySet); - SecureChannelProtocol secProtocol = new SecureChannelProtocol(); + SecureChannelProtocol secProtocol = new SecureChannelProtocol(protocol); // AC: KDF SPEC CHANGE - check for error reading settings if (missingSetting_exception == null) { - if (protocol == 1) { - KeySetData = secProtocol.diversifyKey(oldSelectedToken, + if (protocol == 1 || protocol == 3) { + KeySetData = secProtocol.diversifyKey(oldSelectedToken, newSelectedToken, oldKeyNickName, newKeyNickName, xkeyInfo, // AC: KDF SPEC CHANGE - pass in old key info so symkey can make decision about which KDF version to use @@ -1811,7 +1832,7 @@ public class TokenServlet extends CMSServlet { nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID' xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use - (protocol == 2) ? xWrappedDekKey : kekKeyArray, useSoftToken_s, keySet, (byte) protocol); + kekKeyArray,encKeyArray,macKeyArray, useSoftToken_s, keySet, (byte) protocol,gp3Params); } else if (protocol == 2) { KeySetData = SessionKey.DiversifyKey(oldSelectedToken, newSelectedToken, oldKeyNickName, @@ -1954,6 +1975,8 @@ public class TokenServlet extends CMSServlet { String rKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO); String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID); + String protocolValue = req.getParameter(IRemoteRequest.CHANNEL_PROTOCOL); + // AC: KDF SPEC CHANGE - read new KDD parameter from TPS String rKDD = req.getParameter("KDD"); if ((rKDD == null) || (rKDD.length() == 0)) { @@ -1996,6 +2019,8 @@ public class TokenServlet extends CMSServlet { s_isRandom); audit(auditMessage); + GPParams gp3Params = readGPSettings(keySet); + if (isRandom) { if ((rdata == null) || (rdata.equals(""))) { CMS.debug("TokenServlet: processEncryptData(): no data in request. Generating random number as data"); @@ -2058,7 +2083,7 @@ public class TokenServlet extends CMSServlet { } xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo); - if (xkeyInfo == null || xkeyInfo.length != 2) { + if (xkeyInfo == null || (xkeyInfo.length != 2 && xkeyInfo.length != 3)) { badParams += " KeyInfo length,"; CMS.debug("TokenServlet: Invalid key info length"); missingParam = true; @@ -2103,7 +2128,7 @@ public class TokenServlet extends CMSServlet { data = com.netscape.cmsutil.util.Utils.SpecialDecode(rdata); keyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo); - String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo; + String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo.substring(0,6); String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null); if (mappingValue == null) { selectedToken = CMS.getConfigStore().getString("tks.defaultSlot", CryptoUtil.INTERNAL_TOKEN_NAME); @@ -2114,20 +2139,53 @@ public class TokenServlet extends CMSServlet { keyNickName = st.nextToken(); } + + //calculate the protocol + + int protocolInt = SecureChannelProtocol.PROTOCOL_ONE; + try + { + protocolInt = Integer.parseInt(protocolValue); + } + catch (NumberFormatException nfe) + { + protocolInt = SecureChannelProtocol.PROTOCOL_ONE; + } + + CMS.debug( "TokenServerlet.encryptData: protocol input: " + protocolInt); + + //Check for reasonable sanity, leave room for future versions + if(protocolInt <= 0 || protocolInt > 20) { + CMS.debug( "TokenServerlet.encryptData: unfamliar protocl, assume default of 1."); + protocolInt = 1; + + } + byte kekKeyArray[] = com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + keySet + ".kek_key")); // AC: KDF SPEC CHANGE - check for error reading settings if (missingSetting_exception == null) { - SecureChannelProtocol protocol = new SecureChannelProtocol(); - encryptedData = protocol.encryptData( - selectedToken, keyNickName, data, keyInfo, - nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration file value - nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value - xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID' - xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use - kekKeyArray, useSoftToken_s, keySet); + SecureChannelProtocol protocol = new SecureChannelProtocol(protocolInt); + + if (protocolInt != SecureChannelProtocol.PROTOCOL_THREE) { + + encryptedData = protocol.encryptData( + selectedToken, keyNickName, data, keyInfo, + nistSP800_108KdfOnKeyVersion, // AC: KDF SPEC CHANGE - pass in configuration file value + nistSP800_108KdfUseCuidAsKdd, // AC: KDF SPEC CHANGE - pass in configuration file value + xCUID, // AC: KDF SPEC CHANGE - removed duplicative 'CUID' variable and replaced with 'xCUID' + xKDD, // AC: KDF SPEC CHANGE - pass in KDD so symkey can make decision about which value (KDD,CUID) to use + kekKeyArray, useSoftToken_s, keySet); + + } else { + + encryptedData = protocol.encryptData_SCP03(selectedToken, keyNickName, data, xkeyInfo, + nistSP800_108KdfOnKeyVersion, nistSP800_108KdfUseCuidAsKdd, xCUID, xKDD, kekKeyArray, + useSoftToken_s, keySet,gp3Params); + + } SecureChannelProtocol.debugByteArray(encryptedData, "New Encrypt Data: "); @@ -2402,7 +2460,7 @@ public class TokenServlet extends CMSServlet { //CMS.debug("Protocol: " + protocol + " temp: " + temp); setDefaultSlotAndKeyName(req); - if (temp != null) { + if (temp != null && protocol == null) { processComputeSessionKey(req, resp); } else if (req.getParameter(IRemoteRequest.TOKEN_DATA) != null) { processEncryptData(req, resp); @@ -2413,10 +2471,515 @@ public class TokenServlet extends CMSServlet { } else if (protocol != null && protocol.contains("2") && (derivationConstant != null)) { //SCP02 compute one session key. processComputeSessionKeySCP02(req, resp); + + } else if (protocol != null && protocol.contains("3") ) { + processComputeSessionKeysSCP03(req,resp); } else { throw new EBaseException("Process: Can't decide upon function to call!"); + } + } + + //Create all the session keys for scp03 at once and return. + //ToDo: calcualte the optional rmac key + private void processComputeSessionKeysSCP03(HttpServletRequest req, HttpServletResponse resp) throws EBaseException { + String method = "processComputeSessionKeysSCP03:"; + CMS.debug(method + " entering ..."); + + byte[] card_challenge, host_challenge, xCUID, xKDD; + byte[] card_crypto, host_cryptogram, input_card_crypto; + byte[] xcard_challenge, xhost_challenge; + byte[] enc_session_key, xkeyInfo,mac_session_key, kek_session_key; + String auditMessage = null; + String errorMsg = ""; + String badParams = ""; + String transportKeyName = ""; + String rCUID = req.getParameter(IRemoteRequest.TOKEN_CUID); + + String rKDD = req.getParameter("KDD"); + if ((rKDD == null) || (rKDD.length() == 0)) { + // KDF phase1: default to rCUID if not present + CMS.debug("TokenServlet: KDD not supplied, set to CUID before TPS change"); + rKDD = rCUID; + } + + String keySet = req.getParameter(IRemoteRequest.TOKEN_KEYSET); + if (keySet == null || keySet.equals("")) { + keySet = "defKeySet"; + } + CMS.debug("keySet selected: " + keySet); + + GPParams gp3Params = readGPSettings(keySet); + + boolean serversideKeygen = false; + + IConfigStore sconfig = CMS.getConfigStore(); + boolean isCryptoValidate = true; + boolean missingParam = false; + + Exception missingSetting_exception = null; + + mac_session_key = null; + kek_session_key = null; + card_crypto = null; + host_cryptogram = null; + enc_session_key = null; + + SessionContext sContext = SessionContext.getContext(); + + String agentId = ""; + if (sContext != null) { + agentId = + (String) sContext.get(SessionContext.USER_ID); + } + + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST, + rCUID, + rKDD, + ILogger.SUCCESS, + agentId); + + audit(auditMessage); + + String kek_wrapped_desKeyString = null; + String keycheck_s = null; + + String useSoftToken_s = CMS.getConfigStore().getString("tks.useSoftToken", "true"); + if (!useSoftToken_s.equalsIgnoreCase("true")) + useSoftToken_s = "false"; + + CMS.debug(method + " useSoftToken: " + useSoftToken_s); + + String rServersideKeygen = req.getParameter(IRemoteRequest.SERVER_SIDE_KEYGEN); + if (rServersideKeygen.equals("true")) { + + serversideKeygen = true; + } + + CMS.debug(method + " serversideKeygen: " + serversideKeygen); + + try { + isCryptoValidate = sconfig.getBoolean("cardcryptogram.validate.enable", true); + } catch (EBaseException eee) { + } + + CMS.debug(method + " Do crypto validation: " + isCryptoValidate); + + transportKeyName = getSharedSecretName(sconfig); + + String rcard_challenge = req.getParameter(IRemoteRequest.TOKEN_CARD_CHALLENGE); + String rhost_challenge = req.getParameter(IRemoteRequest.TOKEN_HOST_CHALLENGE); + String rKeyInfo = req.getParameter(IRemoteRequest.TOKEN_KEYINFO); + String rcard_cryptogram = req.getParameter(IRemoteRequest.TOKEN_CARD_CRYPTOGRAM); + + if ((rCUID == null) || (rCUID.equals(""))) { + CMS.debug(method + " missing request parameter: CUID"); + badParams += " CUID,"; + missingParam = true; + } + + if ((rKDD == null) || (rKDD.length() == 0)) { + CMS.debug(method + " missing request parameter: KDD"); + badParams += " KDD,"; + missingParam = true; + } + + if ((rcard_challenge == null) || (rcard_challenge.equals(""))) { + badParams += " card_challenge,"; + CMS.debug(method + " missing request parameter: card challenge"); + missingParam = true; + } + + if ((rhost_challenge == null) || (rhost_challenge.equals(""))) { + badParams += " host_challenge,"; + CMS.debug(method + " missing request parameter: host challenge"); + missingParam = true; + } + + if ((rcard_cryptogram == null) || (rcard_cryptogram.equals(""))) { + badParams += " card_cryptogram,"; + CMS.debug(method + " missing request parameter: card_cryptogram"); + missingParam = true; + } + + if ((rKeyInfo == null) || (rKeyInfo.equals(""))) { + badParams += " KeyInfo,"; + CMS.debug(method + "missing request parameter: key info"); + missingParam = true; + } + + String selectedToken = null; + String keyNickName = null; + boolean sameCardCrypto = true; + + xCUID = null; + xKDD = null; + xkeyInfo = null; + xcard_challenge = null; + xhost_challenge = null; + + if (!missingParam) { + xCUID = com.netscape.cmsutil.util.Utils.SpecialDecode(rCUID); + if (xCUID == null || xCUID.length != 10) { + badParams += " CUID length,"; + CMS.debug("TokenServlet: Invalid CUID length"); + missingParam = true; + } + + xKDD = com.netscape.cmsutil.util.Utils.SpecialDecode(rKDD); + if (xKDD == null || xKDD.length != 10) { + badParams += " KDD length,"; + CMS.debug("TokenServlet: Invalid KDD length"); + missingParam = true; + } + + xkeyInfo = com.netscape.cmsutil.util.Utils.SpecialDecode(rKeyInfo); + if (xkeyInfo == null || xkeyInfo.length != 3) { + badParams += " KeyInfo length,"; + CMS.debug("TokenServlet: Invalid key info length."); + missingParam = true; + } + xcard_challenge = + com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_challenge); + if (xcard_challenge == null || xcard_challenge.length != 8) { + badParams += " card_challenge length,"; + CMS.debug("TokenServlet: Invalid card challenge length."); + missingParam = true; + } + + xhost_challenge = com.netscape.cmsutil.util.Utils.SpecialDecode(rhost_challenge); + if (xhost_challenge == null || xhost_challenge.length != 8) { + badParams += " host_challenge length,"; + CMS.debug("TokenServlet: Invalid host challenge length"); + missingParam = true; + } + } + + ArrayList<String> serverSideValues = null; + + if (!missingParam) { + card_challenge = + com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_challenge); + + host_challenge = com.netscape.cmsutil.util.Utils.SpecialDecode(rhost_challenge); + + String keyInfoMap = "tks." + keySet + ".mk_mappings." + rKeyInfo.substring(0,6); //#xx#xx + String mappingValue = CMS.getConfigStore().getString(keyInfoMap, null); + + + if (mappingValue == null) { + selectedToken = + CMS.getConfigStore().getString("tks.defaultSlot", "internal"); + keyNickName = rKeyInfo; + } else { + StringTokenizer st = new StringTokenizer(mappingValue, ":"); + if (st.hasMoreTokens()) + selectedToken = st.nextToken(); + if (st.hasMoreTokens()) + keyNickName = st.nextToken(); + } + + CMS.debug(method + " selectedToken: " + selectedToken + " keyNickName: " + keyNickName ); + + SymmetricKey macSessionKey = null; + SymmetricKey encSessionKey = null; + SymmetricKey kekSessionKey = null; + + if (selectedToken != null && keyNickName != null + && missingSetting_exception == null) { + + try { + + byte macKeyArray[] = + com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + + keySet + ".mac_key")); + CMS.debug("TokenServlet about to try ComputeSessionKey selectedToken=" + + selectedToken + " keyNickName=" + keyNickName); + + SecureChannelProtocol protocol = new SecureChannelProtocol(SecureChannelProtocol.PROTOCOL_THREE); + + macSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName,xkeyInfo, + SecureChannelProtocol.macType, macKeyArray, keySet,xCUID, xKDD, xhost_challenge, xcard_challenge, + transportKeyName,gp3Params); + + mac_session_key = protocol.wrapSessionKey(selectedToken, macSessionKey, null); + + if (mac_session_key == null) { + CMS.debug(method + " Can't get mac session key bytes"); + throw new Exception(method + " Can't get mac session key bytes"); + + } + + byte encKeyArray[] = + com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + + keySet + ".auth_key")); + + encSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName,xkeyInfo, + SecureChannelProtocol.encType, encKeyArray, keySet, xCUID, xKDD, xhost_challenge, xcard_challenge, + transportKeyName,gp3Params); + + enc_session_key = protocol.wrapSessionKey(selectedToken, encSessionKey, null); + + if (enc_session_key == null) { + CMS.debug("TokenServlet:Tried ComputeEncSessionKey, got NULL "); + throw new Exception("Can't compute enc session key!"); + + } + + byte kekKeyArray[] = + com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + + keySet + ".kek_key")); + + kekSessionKey = protocol.computeSessionKey_SCP03(selectedToken, keyNickName, xkeyInfo, + SecureChannelProtocol.kekType, kekKeyArray, keySet, xCUID, xKDD, xhost_challenge, + xcard_challenge, + transportKeyName,gp3Params); + + kek_session_key = protocol.wrapSessionKey(selectedToken, kekSessionKey, null); + + + //Offload some of the tedious params gathering to another method + //ToDo, create a method that reads all this stuff at once for all major methods + if (serversideKeygen) { + try { + serverSideValues = calculateServerSideKeygenValues(useSoftToken_s, selectedToken, + kekSessionKey, protocol); + } catch (EBaseException e) { + + CMS.debug(method + " Can't calcualte server side keygen required values..."); + + } + } + + try { + isCryptoValidate = sconfig.getBoolean("cardcryptogram.validate.enable", true); + } catch (EBaseException eee) { + } + + ByteArrayOutputStream contextStream = new ByteArrayOutputStream(); + try { + contextStream.write(host_challenge); + contextStream.write(card_challenge); + } catch (IOException e) { + throw new EBaseException(method + " Error calculating derivation data!"); + } + + host_cryptogram = protocol.computeCryptogram_SCP03(macSessionKey, selectedToken, contextStream.toByteArray(),NistSP800_108KDF.HOST_CRYPTO_KDF_CONSTANT); + SecureChannelProtocol.debugByteArray(host_cryptogram, method + " calculated host crypto: " + host_cryptogram.length); + + + if( isCryptoValidate) { + if (rcard_cryptogram == null) { + CMS.debug(method + " missing card cryptogram"); + throw new Exception(method + "Missing card cryptogram"); + } + input_card_crypto = + com.netscape.cmsutil.util.Utils.SpecialDecode(rcard_cryptogram); + card_crypto = protocol.computeCryptogram_SCP03(macSessionKey, selectedToken, contextStream.toByteArray(),NistSP800_108KDF.CARD_CRYPTO_KDF_CONSTANT); + SecureChannelProtocol.debugByteArray(card_crypto, method + " calculated card crypto: "); + SecureChannelProtocol.debugByteArray(input_card_crypto, method + " original card crypto: "); + + if(!cryptoGramsAreEqual(input_card_crypto, card_crypto)) { + throw new Exception(method + "Card cryptogram mismatch!"); + } + + } + } catch (Exception e) { + CMS.debug(e); + CMS.debug("TokenServlet Computing Session Key: " + e.toString()); + if (isCryptoValidate) + sameCardCrypto = false; + } + } + } // ! missingParam + + String value = ""; + + resp.setContentType("text/html"); + + String encSessionKeyString = ""; + String macSessionKeyString = ""; + String kekSessionKeyString = ""; + + String drm_trans_wrapped_desKeyString = ""; + String cryptogram = ""; + String status = "0"; + + if (enc_session_key != null && enc_session_key.length > 0) { + encSessionKeyString = + com.netscape.cmsutil.util.Utils.SpecialEncode(enc_session_key); + } else { + status = "1"; + } + + if (mac_session_key != null && mac_session_key.length > 0) { + macSessionKeyString = + com.netscape.cmsutil.util.Utils.SpecialEncode(mac_session_key); + } else { + status = "1"; + } + + if (kek_session_key != null && kek_session_key.length > 0) { + kekSessionKeyString = + com.netscape.cmsutil.util.Utils.SpecialEncode(kek_session_key); + } else { + status = "1"; + } + + if (serversideKeygen == true) { + if (serverSideValues.size() == 3) { + drm_trans_wrapped_desKeyString = serverSideValues.get(2); + kek_wrapped_desKeyString = serverSideValues.get(0); + keycheck_s = serverSideValues.get(1); + } + else { + status = "1"; + } + } + if (host_cryptogram != null && host_cryptogram.length > 0) { + cryptogram = + com.netscape.cmsutil.util.Utils.SpecialEncode(host_cryptogram); + } else { + if (status.equals("0") == true) { + status = "2"; + } + } + + if (selectedToken == null || keyNickName == null) { + // AC: Bugfix: Don't override status's value if an error was already flagged + if (status.equals("0") == true) { + status = "4"; + } } + + if (!sameCardCrypto) { + if (status.equals("0") == true) { + status = "5"; + } + } + + if (missingSetting_exception != null) { + status = "6"; + } + + if (missingParam) { + status = "3"; + } + + if (!status.equals("0")) { + + if (status.equals("1")) { + errorMsg = "Problem generating session key info."; + } + + if (status.equals("2")) { + errorMsg = "Problem creating host_cryptogram."; + } + + if (status.equals("5")) { + errorMsg = "Card cryptogram mismatch. Token likely has incorrect keys."; + } + + if (status.equals("4")) { + errorMsg = "Problem obtaining token information."; + } + + if (status.equals("6")) { + errorMsg = "Problem reading required configuration value."; + } + + if (status.equals("3")) { + if (badParams.endsWith(",")) { + badParams = badParams.substring(0, badParams.length() - 1); + } + errorMsg = "Missing input parameters :" + badParams; + } + + value = IRemoteRequest.RESPONSE_STATUS + "=" + status; + } else { + if (serversideKeygen == true) { + StringBuffer sb = new StringBuffer(); + sb.append(IRemoteRequest.RESPONSE_STATUS + "=0&"); + sb.append(IRemoteRequest.TKS_RESPONSE_MacSessionKey + "="); + sb.append(macSessionKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_HostCryptogram + "="); + sb.append(cryptogram); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_EncSessionKey + "="); + sb.append(encSessionKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_KekSessionKey + "="); + sb.append(kekSessionKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_KEK_DesKey + "="); + sb.append(kek_wrapped_desKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_KeyCheck + "="); + sb.append(keycheck_s); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey + "="); + sb.append(drm_trans_wrapped_desKeyString); + value = sb.toString(); + } else { + StringBuffer sb = new StringBuffer(); + sb.append(IRemoteRequest.RESPONSE_STATUS + "=0&"); + sb.append(IRemoteRequest.TKS_RESPONSE_MacSessionKey + "="); + sb.append(macSessionKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_HostCryptogram + "="); + sb.append(cryptogram); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_EncSessionKey + "="); + sb.append(encSessionKeyString); + sb.append("&" + IRemoteRequest.TKS_RESPONSE_KekSessionKey + "="); + value = sb.toString(); + } + + } + //CMS.debug(method + "outputString.encode " + value); + + try { + resp.setContentLength(value.length()); + CMS.debug("TokenServlet:outputString.length " + value.length()); + OutputStream ooss = resp.getOutputStream(); + ooss.write(value.getBytes()); + ooss.flush(); + mRenderResult = false; + } catch (IOException e) { + CMS.debug("TokenServlet: " + e.toString()); + } + + if (status.equals("0")) { + String[] logParams = { log_string_from_specialDecoded_byte_array(xCUID), // CUID_decoded + log_string_from_specialDecoded_byte_array(xKDD), // KDD_decoded + ILogger.SUCCESS, // Outcome + status, // status + agentId, // AgentID + isCryptoValidate ? "true" : "false", // IsCryptoValidate + serversideKeygen ? "true" : "false", // IsServerSideKeygen + selectedToken, // SelectedToken + keyNickName, // KeyNickName + keySet, // TKSKeyset + log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion + }; + auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, + logParams); + + } else { + String[] logParams = { log_string_from_specialDecoded_byte_array(xCUID), // CUID_decoded + log_string_from_specialDecoded_byte_array(xKDD), // KDD_decoded + ILogger.FAILURE, // Outcome + status, // status + agentId, // AgentID + isCryptoValidate ? "true" : "false", // IsCryptoValidate + serversideKeygen ? "true" : "false", // IsServerSideKeygen + selectedToken, // SelectedToken + keyNickName, // KeyNickName + keySet, // TKSKeyset + log_string_from_keyInfo(xkeyInfo), // KeyInfo_KeyVersion + errorMsg // Error + }; + auditMessage = CMS.getLogMessage(LOGGING_SIGNED_AUDIT_COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE, + logParams); + + } + + audit(auditMessage); + } /** @@ -2479,4 +3042,197 @@ public class TokenServlet extends CMSServlet { } + //returns ArrayList of following values + // 0 : Kek wrapped des key + // 1 : keycheck value + // 2 : trans wrapped des key + private ArrayList<String> calculateServerSideKeygenValues(String useSoftToken, String selectedToken, + SymmetricKey kekSessionKey, SecureChannelProtocol protocol) throws EBaseException { + + SymmetricKey desKey = null; + String method = "TokenServlet.calculateSErverSideKeygenValues: "; + ArrayList<String> values = new ArrayList<String>(); + + /** + * 0. generate des key + * 1. encrypt des key with kek key + * 2. encrypt des key with DRM transport key + * These two wrapped items are to be sent back to + * TPS. 2nd item is to DRM + **/ + CMS.debug(method + " entering..."); + + // (1) generate DES key + /* applet does not support DES3 + org.mozilla.jss.crypto.KeyGenerator kg = + internalToken.getKeyGenerator(KeyGenAlgorithm.DES3); + desKey = kg.generate();*/ + + /* + * GenerateSymkey firt generates a 16 byte DES2 key. + * It then pads it into a 24 byte key with last + * 8 bytes copied from the 1st 8 bytes. Effectively + * making it a 24 byte DES2 key. We need this for + * wrapping private keys on DRM. + */ + /*generate it on whichever token the master key is at*/ + + if (useSoftToken.equals("true")) { + CMS.debug(method + " key encryption key generated on internal"); + desKey = protocol.generateSymKey("internal"); + //cfu audit here? sym key gen done + } else { + CMS.debug("TokenServlet: key encryption key generated on " + selectedToken); + desKey = protocol.generateSymKey(selectedToken); + } + if (desKey == null) { + throw new EBaseException(method + "can't generate key encryption key"); + } + + /* + * ECBencrypt actually takes the 24 byte DES2 key + * and discard the last 8 bytes before it encrypts. + * This is done so that the applet can digest it + */ + + + // protocol.wrapSessionKey(tokenName, sessionKey, wrappingKey) + + byte[] encDesKey = protocol.ecbEncrypt(kekSessionKey, desKey, selectedToken); + + String kek_wrapped_desKeyString = + com.netscape.cmsutil.util.Utils.SpecialEncode(encDesKey); + + CMS.debug(method + "kek_wrapped_desKeyString: " + kek_wrapped_desKeyString); + + values.add(kek_wrapped_desKeyString); + + // get keycheck + + byte[] keycheck = null; + + keycheck = protocol.computeKeyCheck(desKey, selectedToken); + + String keycheck_s = + com.netscape.cmsutil.util.Utils.SpecialEncode(keycheck); + + CMS.debug(method + "keycheck_s " + keycheck_s); + + values.add(keycheck_s); + + //use DRM transport cert to wrap desKey + String drmTransNickname = CMS.getConfigStore().getString("tks.drm_transport_cert_nickname", ""); + + if ((drmTransNickname == null) || (drmTransNickname == "")) { + CMS.debug(method + " did not find DRM transport certificate nickname"); + throw new EBaseException(method + "can't find DRM transport certificate nickname"); + } else { + CMS.debug(method + " drmtransport_cert_nickname=" + drmTransNickname); + } + + X509Certificate drmTransCert = null; + try { + + drmTransCert = CryptoManager.getInstance().findCertByNickname(drmTransNickname); + // wrap kek session key with DRM transport public key + CryptoToken token = null; + if (useSoftToken.equals("true")) { + //token = CryptoManager.getInstance().getTokenByName(selectedToken); + token = CryptoManager.getInstance().getInternalCryptoToken(); + } else { + token = CryptoManager.getInstance().getTokenByName(selectedToken); + } + PublicKey pubKey = drmTransCert.getPublicKey(); + String pubKeyAlgo = pubKey.getAlgorithm(); + CMS.debug("Transport Cert Key Algorithm: " + pubKeyAlgo); + KeyWrapper keyWrapper = null; + //For wrapping symmetric keys don't need IV, use ECB + if (pubKeyAlgo.equals("EC")) { + keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.AES_ECB); + keyWrapper.initWrap(pubKey, null); + } else { + keyWrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA); + keyWrapper.initWrap(pubKey, null); + } + CMS.debug("desKey token " + desKey.getOwningToken().getName() + " token: " + token.getName()); + byte[] drm_trans_wrapped_desKey = keyWrapper.wrap(desKey); + + String drmWrappedDesStr = + com.netscape.cmsutil.util.Utils.SpecialEncode(drm_trans_wrapped_desKey); + + CMS.debug(method + " drmWrappedDesStr: " + drmWrappedDesStr); + values.add(drmWrappedDesStr); + + } catch (Exception e) { + throw new EBaseException(e); + } + + return values; + } + + private boolean cryptoGramsAreEqual(byte[] original_cryptogram, byte[] calculated_cryptogram) { + boolean sameCardCrypto = true; + + if (original_cryptogram == null || calculated_cryptogram == null) { + return false; + } + if (original_cryptogram.length == calculated_cryptogram.length) { + for (int i = 0; i < original_cryptogram.length; i++) { + if (original_cryptogram[i] != calculated_cryptogram[i]) { + sameCardCrypto = false; + break; + } + } + } else { + // different length; must be different + sameCardCrypto = false; + } + + return sameCardCrypto; + } + + //For now only used for scp03 + + static GPParams readGPSettings(String keySet) { + GPParams params = new GPParams(); + + String method = "TokenServlet.readGPSettings: "; + String gp3Settings = "tks." + keySet + ".prot3"; + + String divers = "emv"; + try { + divers = CMS.getConfigStore().getString(gp3Settings + ".divers", "emv"); + } catch (EBaseException e) { + } + + params.setDiversificationScheme(divers); + + CMS.debug(method + " Divers: " + divers); + + String diversVer1Keys = "emv"; + + try { + diversVer1Keys = CMS.getConfigStore().getString(gp3Settings + ".diversVer1Keys","emv"); + } catch (EBaseException e) { + } + + params.setVersion1DiversificationScheme(diversVer1Keys); + CMS.debug(method + " Version 1 keys Divers: " + divers); + + return params; + } + + private byte[] getDeveKeyArray(String keyType,IConfigStore sconfig,String keySet) throws EBaseException { + byte devKeyArray[] = null; + try { + devKeyArray = com.netscape.cmsutil.util.Utils.SpecialDecode(sconfig.getString("tks." + + keySet + "." + keyType)); + } catch (Exception e) { + throw new EBaseException("Can't read static developer key array: " + keySet + ": " + keyType); + } + + return devKeyArray; + } + + } diff --git a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java index 233124968..82482d09c 100644 --- a/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java +++ b/base/server/cms/src/org/dogtagpki/server/connector/IRemoteRequest.java @@ -53,6 +53,8 @@ public interface IRemoteRequest { /* computeSessionKey responses */ public static final String TKS_RESPONSE_SessionKey = "sessionKey"; public static final String TKS_RESPONSE_EncSessionKey = "encSessionKey"; + public static final String TKS_RESPONSE_MacSessionKey = "macSessionKey"; + public static final String TKS_RESPONSE_KekSessionKey = "kekSessionKey"; public static final String TKS_RESPONSE_KEK_DesKey = "kek_wrapped_desKey"; public static final String TKS_RESPONSE_DRM_Trans_DesKey = "drm_trans_desKey"; public static final String TKS_RESPONSE_KeyCheck = "keycheck"; diff --git a/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java index 90050132b..6e594f849 100644 --- a/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java +++ b/base/server/cmscore/src/com/netscape/cmscore/dbs/KeyRecord.java @@ -18,15 +18,23 @@ package com.netscape.cmscore.dbs; import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Enumeration; import java.util.Vector; +import org.apache.commons.codec.binary.Base64; +import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; +import org.mozilla.jss.crypto.EncryptionAlgorithm; +import org.mozilla.jss.crypto.IVParameterSpec; + import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.MetaInfo; import com.netscape.certsrv.dbs.IDBObj; import com.netscape.certsrv.dbs.keydb.IKeyRecord; import com.netscape.certsrv.dbs.keydb.KeyState; +import com.netscape.certsrv.security.WrappingParams; +import com.netscape.cms.servlet.key.KeyRecordParser; /** * A class represents a Key record. It maintains the key @@ -397,4 +405,101 @@ public class KeyRecord implements IDBObj, IKeyRecord { public String getRealm() throws EBaseException { return realm; } + + public void setWrappingParams(WrappingParams params) throws Exception { + if (mMetaInfo == null) { + mMetaInfo = new MetaInfo(); + } + // set session key parameters + mMetaInfo.set(KeyRecordParser.OUT_SK_LENGTH, String.valueOf(params.getSkLength())); + if (params.getSkType() != null) { + mMetaInfo.set(KeyRecordParser.OUT_SK_TYPE, params.getSkType().toString()); + } + if (params.getSkKeyGenAlgorithm() != null) { + // JSS doesn't have a name map or a functional OID map + // for now, save the "name" + mMetaInfo.set(KeyRecordParser.OUT_SK_KEYGEN_ALGORITHM, params.getSkKeyGenAlgorithm().toString()); + } + if (params.getSkWrapAlgorithm() != null) { + mMetaInfo.set(KeyRecordParser.OUT_SK_WRAP_ALGORITHM, params.getSkWrapAlgorithm().toString()); + } + + // set payload parameters + if (params.getPayloadEncryptionAlgorithm() != null) { + EncryptionAlgorithm encrypt = params.getPayloadEncryptionAlgorithm(); + try { + OBJECT_IDENTIFIER oid = encrypt.toOID(); + mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_OID, oid.toDottedString()); + } catch (NoSuchAlgorithmException e) { + // oid not defined in JSS + mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_ALGORITHM, encrypt.getAlg().toString()); + mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_MODE, encrypt.getMode().toString()); + mMetaInfo.set(KeyRecordParser.OUT_PL_ENCRYPTION_PADDING, encrypt.getPadding().toString()); + } + } + if (params.getPayloadWrapAlgorithm() != null) { + mMetaInfo.set(KeyRecordParser.OUT_PL_WRAP_ALGORITHM, params.getPayloadWrapAlgorithm().toString()); + } + if (params.getPayloadWrappingIV() != null) { + // store as base64 encoded string + mMetaInfo.set( + KeyRecordParser.OUT_PL_WRAP_IV, + Base64.encodeBase64String(params.getPayloadWrappingIV().getIV()) + ); + } + if (params.getPayloadEncryptionIV() != null) { + // store as base 64 encoded string + mMetaInfo.set( + KeyRecordParser.OUT_PL_ENCRYPTION_IV, + Base64.encodeBase64String(params.getPayloadEncryptionIV().getIV()) + ); + } + + } + + public WrappingParams getWrappingParams(WrappingParams oldParams) throws Exception { + if ((mMetaInfo == null) || (mMetaInfo.get(KeyRecordParser.OUT_SK_TYPE) == null)) { + // This is likely a legacy record. Return the old DES3 parameters. + // TODO(alee) modify to pass this in - to keep bean-ness + return oldParams; + } + + WrappingParams params = new WrappingParams(); + params.setSkType(mMetaInfo.get(KeyRecordParser.OUT_SK_TYPE).toString()); + params.setSkLength(Integer.parseInt(mMetaInfo.get(KeyRecordParser.OUT_SK_LENGTH).toString())); + + Object data = mMetaInfo.get(KeyRecordParser.OUT_SK_WRAP_ALGORITHM); + if (data != null) params.setSkWrapAlgorithm(data.toString()); + + data = mMetaInfo.get(KeyRecordParser.OUT_SK_KEYGEN_ALGORITHM); + if (data != null) params.setSkKeyGenAlgorithm(data.toString()); + + data = mMetaInfo.get(KeyRecordParser.OUT_PL_WRAP_ALGORITHM); + if (data != null) params.setPayloadWrapAlgorithm(data.toString()); + + if (mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_OID) != null) { + String oidString = mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_OID).toString(); + params.setPayloadEncryptionAlgorithm(EncryptionAlgorithm.fromOID(new OBJECT_IDENTIFIER(oidString))); + } else { + params.setPayloadEncryptionAlgorithm( + mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_ALGORITHM).toString(), + mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_MODE).toString(), + mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_PADDING).toString(), + Integer.parseInt(mMetaInfo.get(KeyRecordParser.OUT_SK_LENGTH).toString())); + } + + data = mMetaInfo.get(KeyRecordParser.OUT_PL_ENCRYPTION_IV); + if (data != null) { + byte[] iv = Base64.decodeBase64(data.toString()); + params.setPayloadEncryptionIV(new IVParameterSpec(iv)); + } + + data = mMetaInfo.get(KeyRecordParser.OUT_PL_WRAP_IV); + if (data != null) { + byte[] iv = Base64.decodeBase64(data.toString()); + params.setPayloadWrappingIV(new IVParameterSpec(iv)); + } + + return params; + } } diff --git a/base/server/man/man5/pki_default.cfg.5 b/base/server/man/man5/pki_default.cfg.5 index 1eb4ab99b..856081dcf 100644 --- a/base/server/man/man5/pki_default.cfg.5 +++ b/base/server/man/man5/pki_default.cfg.5 @@ -107,7 +107,7 @@ If an optional hardware security module (HSM) is being utilized (rather than the .SS SYSTEM CERTIFICATE PARAMETERS \fBpkispawn\fP sets up a number of system certificates for each subsystem. The system certificates which are required differ between subsystems. Each system certificate is denoted by a tag, as noted below. The different system certificates are: .IP -* signing certificate ("signing"). Used to sign other certificates. Required for CA. +* signing certificate ("ca_signing"). Used to sign other certificates. Required for CA. .IP * OCSP signing certificate ("ocsp_signing" in CA, "signing" in OCSP). Used to sign CRLs. Required for OCSP and CA. .IP diff --git a/base/server/man/man8/pkispawn.8 b/base/server/man/man8/pkispawn.8 index 40ec7f0ad..002520a0b 100644 --- a/base/server/man/man8/pkispawn.8 +++ b/base/server/man/man8/pkispawn.8 @@ -1387,7 +1387,7 @@ Directory Server and Admin Server instances can be created with the following command: .IP -\fBsetup-ds-admin.pl\fP +\fBsetup-ds.pl\fP .PP Enable LDAPS in the Directory Server with the following command: diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py index d556312a7..70734c3db 100644 --- a/base/server/python/pki/server/__init__.py +++ b/base/server/python/pki/server/__init__.py @@ -568,19 +568,7 @@ class PKIInstance(object): # load passwords self.passwords.clear() if os.path.exists(self.password_conf): - - lines = open(self.password_conf).read().splitlines() - - for index, line in enumerate(lines): - if not line or line.startswith('#'): - continue - parts = line.split('=', 1) - if len(parts) < 2: - raise Exception('Missing delimiter in %s line %d' % - (self.password_conf, index + 1)) - name = parts[0] - value = parts[1] - self.passwords[name] = value + pki.util.load_properties(self.password_conf, self.passwords) self.load_external_certs(self.external_certs_conf) diff --git a/base/tks/src/org/dogtagpki/server/tks/rest/TPSConnectorService.java b/base/tks/src/org/dogtagpki/server/tks/rest/TPSConnectorService.java index a2d18f166..9119d7779 100644 --- a/base/tks/src/org/dogtagpki/server/tks/rest/TPSConnectorService.java +++ b/base/tks/src/org/dogtagpki/server/tks/rest/TPSConnectorService.java @@ -1,9 +1,7 @@ package org.dogtagpki.server.tks.rest; import java.io.CharConversionException; -import java.io.IOException; import java.net.URI; -import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -25,7 +23,6 @@ import org.jboss.resteasy.plugins.providers.atom.Link; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.CryptoManager.NotInitializedException; import org.mozilla.jss.crypto.CryptoToken; -import org.mozilla.jss.crypto.InvalidKeyFormatException; import org.mozilla.jss.crypto.KeyGenAlgorithm; import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.SymmetricKey; @@ -347,12 +344,10 @@ public class TPSConnectorService extends PKIService implements TPSConnectorResou return createOKResponse(keyData); - } catch (InvalidKeyException | IllegalStateException | NoSuchAlgorithmException - | InvalidAlgorithmParameterException | EBaseException - | NotInitializedException | TokenException | IOException | InvalidKeyFormatException e) { + } catch (Exception e) { e.printStackTrace(); CMS.debug("Error in generating and exporting shared secret: " + e); - throw new PKIException("Error in generating and exporting shared secret: " + e); + throw new PKIException("Error in generating and exporting shared secret: " + e, e); } } @@ -418,12 +413,10 @@ public class TPSConnectorService extends PKIService implements TPSConnectorResou return createOKResponse(keyData); - } catch (InvalidKeyException | IllegalStateException | NoSuchAlgorithmException - | InvalidAlgorithmParameterException | EBaseException - | NotInitializedException | TokenException | IOException | InvalidKeyFormatException e) { + } catch (Exception e) { e.printStackTrace(); CMS.debug("Error in replacing shared secret: " + e); - throw new PKIException("Error in replacing shared secret: " + e); + throw new PKIException("Error in replacing shared secret: " + e, e); } } @@ -504,12 +497,10 @@ public class TPSConnectorService extends PKIService implements TPSConnectorResou return createOKResponse(keyData); - } catch (InvalidKeyException | IllegalStateException | NoSuchAlgorithmException - | InvalidAlgorithmParameterException | EBaseException - | NotInitializedException | TokenException | IOException | InvalidKeyFormatException e) { + } catch (Exception e) { e.printStackTrace(); CMS.debug("Error in obtaining shared secret: " + e); - throw new PKIException("Error in obtaining shared secret: " + e); + throw new PKIException("Error in obtaining shared secret: " + e, e); } } diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/PlatformAndSecChannelProtoInfo.java b/base/tps/src/org/dogtagpki/server/tps/channel/PlatformAndSecChannelProtoInfo.java index e5f38e108..e1de8f23d 100644 --- a/base/tps/src/org/dogtagpki/server/tps/channel/PlatformAndSecChannelProtoInfo.java +++ b/base/tps/src/org/dogtagpki/server/tps/channel/PlatformAndSecChannelProtoInfo.java @@ -62,6 +62,14 @@ public class PlatformAndSecChannelProtoInfo { } return false; } + + public boolean isSCP03() { + if(protocol == SecureChannel.SECURE_PROTO_03) { + return true; + } + return false; + } + public void setProtocol(byte protocol) { this.protocol = protocol; } diff --git a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java index f2e32368f..fc5472c79 100644 --- a/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java +++ b/base/tps/src/org/dogtagpki/server/tps/channel/SecureChannel.java @@ -65,15 +65,22 @@ public class SecureChannel { public TPSProcessor processor; private PK11SymKey sessionKey; - //SCP01 or SCP02 key + //SCP01 or SCP02 or SCP03 key private PK11SymKey encSessionKey; + //SCP02 session keys private PK11SymKey cmacSessionKey; //Used for security level we do not yet suport. + + + private PK11SymKey rmacSessionKey; private PK11SymKey dekSessionKey; + //SCP03 + private PK11SymKey macSessionKey; + private TPSBuffer dekSessionKeyWrapped; private TPSBuffer drmDesKey; @@ -112,11 +119,65 @@ public class SecureChannel { public final static byte[] GP201_GET_DATA_CPLC_WHOLE_CPLC = { (byte) 0x9F, (byte) 0x7F }; public final static byte[] GP211_GET_DATA_CPLC_WHOLE_CPLC = { (byte) 0x9F, (byte) 0x7F }; + // SCP02 public final static byte[] C_MACDerivationConstant = { 0x01, 0x01 }; public final static byte[] ENCDerivationConstant = { (byte) 0x01, (byte) 0x82 }; public final static byte[] DEKDerivationConstant = { 0x01, (byte) 0x81 }; public final static byte[] R_MACDerivationConstant = { 0x01, 0x02 }; + //SCP03 encryption counter + + private TPSBuffer encryptionCounter; + + + //For SCP03 + + public SecureChannel(TPSProcessor processor, PK11SymKey encSessionKey, PK11SymKey macSessionKey, PK11SymKey dekSessionKey, + TPSBuffer drmDesKey,TPSBuffer kekDesKey, + TPSBuffer keyCheck, TPSBuffer keyDiversificationData, TPSBuffer cardChallenge, + TPSBuffer cardCryptogram, TPSBuffer hostChallenge, TPSBuffer hostCryptogram, TPSBuffer keyInfoData, + PlatformAndSecChannelProtoInfo platformInfo) + throws TPSException { + + if (processor == null || encSessionKey == null || keyDiversificationData == null + || cardChallenge == null || cardCryptogram == null || hostChallenge == null || hostCryptogram == null + || keyInfoData == null) { + throw new TPSException("SecureChannel.SecureChannel: Invalid data in constructor!", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + CMS.debug("SecureChannel.SecureChannel: For SCP03. : "); + + CMS.debug("kekDesKey: " + kekDesKey.toHexString()); + CMS.debug("keyCheck: " + keyCheck.toHexString()); + + this.platProtInfo = platformInfo; + this.processor = processor; + this.encSessionKey = encSessionKey; + this.macSessionKey = macSessionKey; + this.dekSessionKey = dekSessionKey; + + this.drmDesKey = drmDesKey; + this.setKekDesKey(kekDesKey); + + this.keyCheck = keyCheck; + this.keyDiversificationData = keyDiversificationData; + this.cardChallenge = cardChallenge; + this.cardCryptogram = cardCryptogram; + this.hostChallenge = hostChallenge; + this.hostCryptogram = hostCryptogram; + + //16 bytes of chaining value + this.icv = new TPSBuffer(16); + + this.keyInfoData = keyInfoData; + + this.secLevel = SecurityLevel.SECURE_MSG_NONE; + this.secLevelGP211 = ExternalAuthenticateAPDUGP211.SecurityLevel.CDEC_CMAC; + encryptionCounter = new TPSBuffer(16); + + } + //For SCP01 public SecureChannel(TPSProcessor processor, PK11SymKey sessionKey, PK11SymKey encSessionKey, TPSBuffer drmDesKey, TPSBuffer kekDesKey, TPSBuffer keyCheck, TPSBuffer keyDiversificationData, TPSBuffer cardChallenge, @@ -345,12 +406,46 @@ public class SecureChannel { public void externalAuthenticate() throws TPSException, IOException { - CMS.debug("SecureChannel.externalAuthenticate: entering. &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); + String method = "SecureChannel.externalAuthenticate."; + CMS.debug(method + ": entering. &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"); - if (platProtInfo.isGP211() && platProtInfo.isSCP02()) { + TPSBuffer calculatedCardCryptogram = null; + if(platProtInfo.isSCP03()) { + CMS.debug("SecureChannel.externalAuthenticate: Attempting an External Authenticate for SCP03!"); + + TPSBuffer context = new TPSBuffer(hostChallenge); + context.add(cardChallenge); + try { + calculatedCardCryptogram = Util.compute_AES_CMAC_Cryptogram(macSessionKey, context, Util.CARD_CRYPTO_KDF_CONSTANT_SCP03); + } catch (EBaseException e) { + throw new TPSException(method + "Failed to calculate card cryptogram!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + CMS.debug(method + " dumped macSessionKey: " + new TPSBuffer(macSessionKey.getEncoded()).toHexString() ); + + CMS.debug(method + " actual card cryptogram " + cardCryptogram.toHexString()); + CMS.debug(method + " calculated card cryptogram " + calculatedCardCryptogram.toHexString()); + + ExternalAuthenticateAPDUGP211 externalAuth = new ExternalAuthenticateAPDUGP211(hostCryptogram, + /* secLevel */secLevelGP211); + + computeAPDUMacSCP03(externalAuth); + + APDUResponse response = processor.handleAPDURequest(externalAuth); + + if (!response.checkResult()) { + throw new TPSException( + "SecureChannel.eternalAuthenticate SCP03. Failed to external authenticate to token.", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + } + + + if (platProtInfo.isSCP02()) { CMS.debug("SecureChannel.externalAuthenticate: Attempting an External Authenticate for SCP02!"); - TPSBuffer calculatedCardCryptogram = computeCardCryptogramSCP02(encSessionKey); + calculatedCardCryptogram = computeCardCryptogramSCP02(encSessionKey); if (false == cardCryptogram.equals(calculatedCardCryptogram)) { @@ -383,7 +478,7 @@ public class SecureChannel { CMS.debug("SecureChannel.externalAuthenticate: SCP02 external authenticate returns Success!!!"); - } else { //SCP01 + } else if(platProtInfo.isSCP01()){ //SCP01 ExternalAuthenticateAPDU externalAuth = new ExternalAuthenticateAPDU(hostCryptogram, /* secLevel */ExternalAuthenticateAPDU.SecurityLevel.SECURE_MSG_MAC_ENC); @@ -410,15 +505,20 @@ public class SecureChannel { CMS.debug("SecureChannel.computeAPDU: entering.."); + if (apdu == null) { + throw new TPSException("SecureChannel.computeAPDU: bad input apdu!", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + if (isSCP02()) { computeAPDU_SCP02(apdu); return; } - if (apdu == null) { - throw new TPSException("SecureChannel.computeAPDU: bad input apdu!", - TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + if (isSCP03() ) { + computeAPDU_SCP03(apdu); + return; } computeAPDUMac(apdu); @@ -436,6 +536,60 @@ public class SecureChannel { } } + private void computeAPDU_SCP03(APDU apdu) throws TPSException { + String method = "SecureChannel.computeAPDU_SCP03:"; + + CMS.debug(method + "entering.."); + if (apdu == null) { + throw new TPSException(method + " bad input apdu!", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + if (secLevelGP211 == ExternalAuthenticateAPDUGP211.SecurityLevel.CDEC_CMAC) { + try { + //CMS.debug("SecureChannel.computeAPDU_SCP03: Before encryption data value: " + // + apdu.getData().toHexString()); + this.incrementBuffer(encryptionCounter); + TPSBuffer currentEncryptionCounter = new TPSBuffer(encryptionCounter); + apdu.secureMessageSCP03(encSessionKey,currentEncryptionCounter); + ; + //CMS.debug("SecureChannel.computeAPDU_SCP03: After encryption data value: " + // + apdu.getData().toHexString()); + } catch (EBaseException e) { + throw new TPSException("SecureChannel.computeAPDU_SCP03: Can't encrypt outgoing data! " + e); + } + + CMS.debug("SecureChannel.computeAPDU_SCP03: Successfully encrypted apdu data."); + } + + computeAPDUMacSCP03(apdu); + } + + //Assume the whole buffer is to be incremented + //Used for SCP03 encrypted apdu messages + public void incrementBuffer(TPSBuffer buffer) { + + if(buffer == null) + return; + + int len = buffer.size(); + + if (len < 1) + return; + int offset = 0; + for (short i = (short) (offset + len - 1); i >= offset; i--) { + byte cur = buffer.at(i); + if (cur != (byte) 0xFF) { + cur++; + buffer.setAt(i, cur); + break; + } else + buffer.setAt(i,(byte) 0x00); + } + + System.out.println("enc buffer: " + buffer.toHexString()); + } + private void computeAPDU_SCP02(APDU apdu) throws TPSException { CMS.debug("SecureChannel.computeAPDU_SCP02: entering.."); @@ -448,11 +602,11 @@ public class SecureChannel { if (secLevelGP211 == ExternalAuthenticateAPDUGP211.SecurityLevel.CDEC_CMAC) { try { - CMS.debug("SecureChannel.computeAPDU_SCP02: Before encryption data value: " - + apdu.getData().toHexString()); + //CMS.debug("SecureChannel.computeAPDU_SCP02: Before encryption data value: " + // + apdu.getData().toHexString()); apdu.secureMessageSCP02(encSessionKey); - CMS.debug("SecureChannel.computeAPDU_SCP02: After encryption data value: " - + apdu.getData().toHexString()); + //CMS.debug("SecureChannel.computeAPDU_SCP02: After encryption data value: " + // + apdu.getData().toHexString()); } catch (EBaseException e) { throw new TPSException("SecureChannel.computeAPDU_SCP02: Can't encrypt outgoing data! " + e); } @@ -462,6 +616,48 @@ public class SecureChannel { } + private void computeAPDUMacSCP03(APDU apdu) throws TPSException { + TPSBuffer newMac = null; + TPSBuffer data = null; + + if (apdu == null) { + throw new TPSException("SecureChannel.computeAPDUMacSCP03: bad input apdu!", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + data = apdu.getDataToMAC(); + + //CMS.debug("SecureChannel.computeAPDUMacSCP03: data To MAC: " + data.toHexString() + " incoming icv: " + // + icv.toHexString()); + + try { + + CMS.debug("SecureChannel.computeAPDUMacSCP03: No ecnrypton of ICV."); + + TPSBuffer dataToMac = new TPSBuffer(icv); + /// Prepend the chaining value to the data to be maced. + dataToMac.add(data); + + //CMS.debug("SecureChannel.computeAPDUMacSCP03: final data To MAC: " + dataToMac.toHexString() + " incoming icv: " + // + icv.toHexString()); + + newMac = Util.computeAES_CMAC(macSessionKey, dataToMac); + + + } catch (EBaseException e) { + CMS.debug("SecureChannel.computeAPDUMacSCP03: Can't compute mac. " + e); + throw new TPSException("SecureChannel.compuatAPDUMacSCP03: Can't compute mac.", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + CMS.debug("SecureChannel.computeAPDUMacSCP03: computed MAC: " /* + newMac.toHexString() */); + + apdu.setMAC(newMac.substr(0,8)); + + icv.set(newMac); + + } + private void computeAPDUMacSCP02(APDU apdu) throws TPSException { TPSBuffer newMac = null; @@ -571,7 +767,7 @@ public class SecureChannel { public void installLoad(TPSBuffer packageAID, TPSBuffer sdAID, int fileLength) throws TPSException, IOException { CMS.debug("SecureChannel.installLoad: entering ... packageAID: " + packageAID.toHexString() + " sdAID: " - + sdAID.toHexString()); + + sdAID.toHexString() + " fileLength: " + fileLength); if (packageAID == null || sdAID == null || fileLength <= 0) { throw new TPSException("SecureChannel.insallLoad bad input parameters!", @@ -1363,14 +1559,15 @@ public class SecureChannel { PutKeyAPDU putKey = new PutKeyAPDU(keyVersion, (byte) 0x81, keySetData); - if (isSCP02()) { + if (isSCP02() || isSCP03()) { + CMS.debug("SecureChannel.putKeys: adding trailing 0 byte"); TPSBuffer trailer = new TPSBuffer(1); putKey.setTrailer(trailer); } computeAPDU(putKey); - int kill = 0; + int kill = 0; if (kill == 1) { throw new TPSException("putKeys end of progress."); } @@ -1503,6 +1700,13 @@ public class SecureChannel { } + public boolean isSCP03() { + if (platProtInfo.isSCP03()) + return true; + else + return false; + } + public boolean isSCP02() { if (platProtInfo.isGP211() && platProtInfo.isSCP02()) { diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java index 2fe382539..910294e53 100644 --- a/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java +++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSComputeSessionKeyResponse.java @@ -62,4 +62,12 @@ public class TKSComputeSessionKeyResponse extends RemoteResponse public TPSBuffer getKekWrappedDesKey() { return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KEK_DesKey); } + + public TPSBuffer getKekSessionKey() { + return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_KekSessionKey); + } + + public TPSBuffer getMacSessionKey() { + return (TPSBuffer) nameValTable.get(IRemoteRequest.TKS_RESPONSE_MacSessionKey); + } } diff --git a/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java b/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java index f38d7def5..65d0ed0ac 100644 --- a/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java +++ b/base/tps/src/org/dogtagpki/server/tps/cms/TKSRemoteRequestHandler.java @@ -226,6 +226,157 @@ public class TKSRemoteRequestHandler extends RemoteRequestHandler } } + public TKSComputeSessionKeyResponse computeSessionKeysSCP03( + TPSBuffer kdd + ,TPSBuffer cuid, + TPSBuffer keyInfo, + TPSBuffer card_challenge, + TPSBuffer card_cryptogram, + TPSBuffer host_challenge, + String tokenType) throws EBaseException { + + String method = "TKSRemoteRequestHandler: computeSessionKeysSCP03()"; + + CMS.debug(method + " Entering: "); + + if (cuid == null || kdd == null || keyInfo == null || card_challenge == null || + card_cryptogram == null || host_challenge == null || tokenType == null + + ) { + throw new EBaseException(method + " invalid input!"); + } + + IConfigStore conf = CMS.getConfigStore(); + + boolean serverKeygen = + conf.getBoolean("op.enroll." + + tokenType + ".keyGen.encryption.serverKeygen.enable", + false); + if (keySet == null) + keySet = conf.getString("tps.connector." + connid + ".keySet", "defKeySet"); + + TPSSubsystem subsystem = + (TPSSubsystem) CMS.getSubsystem(TPSSubsystem.ID); + HttpConnector conn = + (HttpConnector) subsystem.getConnectionManager().getConnector(connid); + + String requestString = IRemoteRequest.SERVER_SIDE_KEYGEN + "=" + serverKeygen + + "&" + IRemoteRequest.TOKEN_KDD + "=" + Util.specialURLEncode(kdd) + + "&" + IRemoteRequest.TOKEN_CUID + "=" + Util.specialURLEncode(cuid) + + "&" + IRemoteRequest.TOKEN_CARD_CHALLENGE + "=" + Util.specialURLEncode(card_challenge) + + "&" + IRemoteRequest.TOKEN_HOST_CHALLENGE + "=" + Util.specialURLEncode(host_challenge) + + "&" + IRemoteRequest.TOKEN_KEYINFO + "=" + Util.specialURLEncode(keyInfo) + + "&" + IRemoteRequest.CHANNEL_PROTOCOL + "=" + SecureChannel.SECURE_PROTO_03 + + "&" + IRemoteRequest.TOKEN_CARD_CRYPTOGRAM + "=" + + Util.specialURLEncode(card_cryptogram.toBytesArray()) + + "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet; + + HttpResponse resp = + conn.send("computeSessionKey", + requestString + ); + + String content = resp.getContent(); + + if (content != null && !content.equals("")) { + Hashtable<String, Object> response = + parseResponse(content); + + /* + * When a value is not found in response, keep going so we know + * what else is missing + * Note: serverKeygen and !serverKeygen returns different set of + * response values so "missing" might not be bad + */ + Integer ist = new Integer(IRemoteRequest.RESPONSE_STATUS_NOT_FOUND); + String value = (String) response.get(IRemoteRequest.RESPONSE_STATUS); + if (value == null) { + CMS.debug(method + " status not found."); + //CMS.debug("TKSRemoteRequestHandler: computeSessionKeySCP02(): got content = " + content); + } else { + CMS.debug(method + " got status = " + value); + ist = Integer.parseInt(value); + } + response.put(IRemoteRequest.RESPONSE_STATUS, ist); + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_EncSessionKey); + if (value == null) { + CMS.debug(method + " response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_EncSessionKey); + } else { + CMS.debug(method+ "got IRemoteRequest.TKS_RESPONSE_EncSessionKey"); + response.put(IRemoteRequest.TKS_RESPONSE_EncSessionKey, Util.specialDecode(value)); + } + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey); + if (value == null) { + CMS.debug(method + " response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey); + } else { + CMS.debug(method + "got IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey"); + response.put(IRemoteRequest.TKS_RESPONSE_DRM_Trans_DesKey, Util.specialDecode(value)); + } + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_MacSessionKey); + if (value == null) { + CMS.debug(method + "response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_MacSessionKey); + } else { + CMS.debug(method + " got IRemoteRequest.TKS_RESPONSE_MacSessionKey"); + response.put(IRemoteRequest.TKS_RESPONSE_MacSessionKey, Util.specialDecode(value)); + + } + + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KekSessionKey); + if (value == null) { + CMS.debug(method + "response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_KekSessionKey); + } else { + CMS.debug(method + " got IRemoteRequest.TKS_RESPONSE_KekSessionKey"); + response.put(IRemoteRequest.TKS_RESPONSE_KekSessionKey, Util.specialDecode(value)); + } + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KEK_DesKey); + if (value == null) { + CMS.debug(method + "response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_KEK_DesKey); + } else { + CMS.debug(method + " got IRemoteRequest.TKS_RESPONSE_KEK_DesKey"); + response.put(IRemoteRequest.TKS_RESPONSE_KEK_DesKey, Util.specialDecode(value)); + + } + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_KeyCheck); + + if (value == null) { + CMS.debug(method + "response missing name-value pair for: " + + IRemoteRequest.TKS_RESPONSE_KeyCheck); + + } else { + CMS.debug(method + " got IRemoteRequest.TKS_RESPONSE_KeyCheck"); + response.put(IRemoteRequest.TKS_RESPONSE_KeyCheck, Util.specialDecode(value)); + } + + value = (String) response.get(IRemoteRequest.TKS_RESPONSE_HostCryptogram); + if ( value == null ) { + CMS.debug(method + " response missing name-value pair for: " + IRemoteRequest.TKS_RESPONSE_HostCryptogram); + } else { + CMS.debug(method + " got " + IRemoteRequest.TKS_RESPONSE_HostCryptogram); + response.put(IRemoteRequest.TKS_RESPONSE_HostCryptogram, Util.specialDecode(value)); + } + + CMS.debug(method + " ends."); + + return new TKSComputeSessionKeyResponse(response); + + } else { + CMS.debug("TKSRemoteRequestHandler: computeSessionKeySCP02(): no response content."); + throw new EBaseException("TKSRemoteRequestHandler: computeSessionKeySCP02(): no response content."); + } + + } + /* * computeSessionKey * @@ -559,7 +710,7 @@ public class TKSRemoteRequestHandler extends RemoteRequestHandler TPSBuffer kdd, TPSBuffer cuid, TPSBuffer version, - TPSBuffer inData) + TPSBuffer inData,int protocol) throws EBaseException { CMS.debug("TKSRemoteRequestHandler: encryptData(): begins."); if (cuid == null || kdd == null || version == null || inData == null) { @@ -582,7 +733,9 @@ public class TKSRemoteRequestHandler extends RemoteRequestHandler "&" + IRemoteRequest.TOKEN_CUID + "=" + Util.specialURLEncode(cuid) + "&" + IRemoteRequest.TOKEN_KDD + "=" + Util.specialURLEncode(kdd) + "&" + IRemoteRequest.TOKEN_KEYINFO + "=" + Util.specialURLEncode(version) + - "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet); + "&" + IRemoteRequest.TOKEN_KEYSET + "=" + keySet + + "&" + IRemoteRequest.CHANNEL_PROTOCOL + "=" + protocol + ); String content = resp.getContent(); diff --git a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java index 319ff67b5..540da4019 100644 --- a/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java +++ b/base/tps/src/org/dogtagpki/server/tps/engine/TPSEngine.java @@ -250,6 +250,48 @@ public class TPSEngine { } + // Compute 3 session keys enc, mac, and kek / dek in one shot and return the results + public TKSComputeSessionKeyResponse computeSessionKeysSCP03(TPSBuffer kdd, TPSBuffer cuid, + TPSBuffer keyInfo, + TPSBuffer card_challenge, + TPSBuffer host_challenge, + TPSBuffer card_cryptogram, + String connId, + String tokenType, String inKeySet) throws TPSException { + + if (cuid == null || kdd == null || keyInfo == null || card_challenge == null || host_challenge == null + || card_cryptogram == null || connId == null || tokenType == null) { + + throw new TPSException("TPSEngine.computeSessionKeySCP03: Invalid input data!", + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + CMS.debug("TPSEngine.computeSessionKeysSCP03"); + + TKSRemoteRequestHandler tks = null; + + TKSComputeSessionKeyResponse resp = null; + try { + tks = new TKSRemoteRequestHandler(connId, inKeySet); + resp = tks.computeSessionKeysSCP03(kdd, cuid, keyInfo, card_challenge, card_cryptogram, host_challenge, + tokenType); + } catch (EBaseException e) { + throw new TPSException("TPSEngine.computeSessionKeysSCP03: Error computing session keys!" + e, + TPSStatus.STATUS_ERROR_SECURE_CHANNEL); + } + + int status = resp.getStatus(); + if (status != 0) { + CMS.debug("TPSEngine.computeSessionKeysSCP03: Non zero status result: " + status); + throw new TPSException("TPSEngine.computeSessionKeysSCP03: invalid returned status: " + status); + + } + + return resp; + + } + + public TKSComputeSessionKeyResponse computeSessionKey(TPSBuffer kdd, TPSBuffer cuid, TPSBuffer keyInfo, TPSBuffer card_challenge, @@ -378,10 +420,12 @@ public class TPSEngine { public TPSBuffer createKeySetData(TPSBuffer newMasterVersion, TPSBuffer oldVersion, int protocol, TPSBuffer cuid, TPSBuffer kdd, TPSBuffer wrappedDekSessionKey, String connId, String inKeyset) throws TPSException { - CMS.debug("TPSEngine.createKeySetData. entering..."); + + String method = "TPSEngine.createKeySetData:"; + CMS.debug(method + " entering..."); if (newMasterVersion == null || oldVersion == null || cuid == null || kdd == null || connId == null) { - throw new TPSException("TPSEngine.createKeySetData: Invalid input data", + throw new TPSException(method + " Invalid input data", TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER); } @@ -394,14 +438,14 @@ public class TPSEngine { resp = tks.createKeySetData(newMasterVersion, oldVersion, cuid, kdd, protocol,wrappedDekSessionKey); } catch (EBaseException e) { - throw new TPSException("TPSEngine.createKeySetData, failure to get key set data from TKS", + throw new TPSException(method + " failure to get key set data from TKS", TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER); } int status = resp.getStatus(); if (status != 0) { - CMS.debug("TPSEngine.createKeySetData: Non zero status result: " + status); - throw new TPSException("TPSEngine.computeSessionKey: invalid returned status: " + status, + CMS.debug(method + " Non zero status result: " + status); + throw new TPSException(method + " invalid returned status: " + status, TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER); } @@ -409,8 +453,8 @@ public class TPSEngine { TPSBuffer keySetData = resp.getKeySetData(); if (keySetData == null) { - CMS.debug("TPSEngine.createKeySetData: No valid key set data returned."); - throw new TPSException("TPSEngine.createKeySetData: No valid key set data returned.", + CMS.debug(method + " No valid key set data returned."); + throw new TPSException(method + " No valid key set data returned.", TPSStatus.STATUS_ERROR_KEY_CHANGE_OVER); } diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java index 8b6370337..672f53d83 100644 --- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java +++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSEnrollProcessor.java @@ -378,8 +378,10 @@ public class TPSEnrollProcessor extends TPSProcessor { String tksConnId = getTKSConnectorID(); TPSBuffer plaintextChallenge = computeRandomData(16, tksConnId); + CMS.debug(method + " plaintextChallenge: " + plaintextChallenge.toHexString()); + //These will be used shortly - TPSBuffer wrappedChallenge = encryptData(appletInfo, channel.getKeyInfoData(), plaintextChallenge, tksConnId); + TPSBuffer wrappedChallenge = encryptData(appletInfo, channel.getKeyInfoData(), plaintextChallenge, tksConnId,this.getProtocol()); PKCS11Obj pkcs11objx = null; try { @@ -3006,7 +3008,7 @@ public class TPSEnrollProcessor extends TPSProcessor { //CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8 : keyCheck: " + keyCheck.toHexString()); CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8 : got keyCheck"); - // String ivParams = ssKeyGenResponse.getIVParam(); + //String ivParams = ssKeyGenResponse.getIVParam(); //CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: ivParams: " + ivParams); TPSBuffer ivParamsBuff = new TPSBuffer(Util.uriDecodeFromHex(ivParams)); @@ -3019,7 +3021,7 @@ public class TPSEnrollProcessor extends TPSProcessor { TPSBuffer kekWrappedDesKey = channel.getKekDesKey(); if (kekWrappedDesKey != null) { - //CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: keyWrappedDesKey: " + kekWrappedDesKey.toHexString()); + CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: keyWrappedDesKey: " + kekWrappedDesKey.toHexString()); CMS.debug("TPSEnrollProcessor.importPrivateKeyPKCS8: got keyWrappedDesKey"); } else CMS.debug("TPSEnrollProcessor.iportPrivateKeyPKC8: null kekWrappedDesKey!"); @@ -3041,7 +3043,7 @@ public class TPSEnrollProcessor extends TPSProcessor { } data.add((byte) ivParamsBuff.size()); data.add(ivParamsBuff); - //CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8: key data outgoing: " + data.toHexString()); + CMS.debug("TPSEnrollProcessor.importprivateKeyPKCS8: key data outgoing: " + data.toHexString()); int pe1 = (cEnrollInfo.getKeyUser() << 4) + cEnrollInfo.getPrivateKeyNumber(); int pe2 = (cEnrollInfo.getKeyUsage() << 4) + cEnrollInfo.getPublicKeyNumber(); diff --git a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java index 825df3f23..7d17f36b7 100644 --- a/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java +++ b/base/tps/src/org/dogtagpki/server/tps/processor/TPSProcessor.java @@ -33,6 +33,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import netscape.security.x509.RevocationReason; + import org.dogtagpki.server.tps.TPSSession; import org.dogtagpki.server.tps.TPSSubsystem; import org.dogtagpki.server.tps.authentication.AuthUIParameter; @@ -99,8 +101,6 @@ import com.netscape.cms.servlet.tks.SecureChannelProtocol; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.symkey.SessionKey; -import netscape.security.x509.RevocationReason; - public class TPSProcessor { public static final int RESULT_NO_ERROR = 0; @@ -111,10 +111,14 @@ public class TPSProcessor { public static final int CPLC_MSN_SIZE = 4; public static final int INIT_UPDATE_DATA_SIZE = 28; + public static final int INIT_UPDATE_DATA_SIZE_02 = 29; + public static final int INIT_UPDATE_DATA_SIZE_03 = 32; public static final int DIVERSIFICATION_DATA_SIZE = 10; public static final int CARD_CRYPTOGRAM_OFFSET = 20; + public static final int CARD_CRYPTOGRAM_OFFSET_GP211_SC03 = 21; public static final int CARD_CRYPTOGRAM_SIZE = 8; public static final int CARD_CHALLENGE_SIZE_GP211_SC02 = 6; + public static final int CARD_CHALLENGE_OFFSET_GP211_SC03 = 13 ; public static final int SEQUENCE_COUNTER_OFFSET_GP211_SC02 = 12; public static final int SEQUENCE_COUNTER_SIZE_GP211_SC02 = 2; public static final int CARD_CHALLENGE_OFFSET = 12; @@ -431,7 +435,7 @@ public class TPSProcessor { protected TPSBuffer encryptData(AppletInfo appletInfo, TPSBuffer keyInfo, TPSBuffer plaintextChallenge, - String connId) throws TPSException { + String connId,int protocol) throws TPSException { TKSRemoteRequestHandler tks = null; @@ -439,7 +443,7 @@ public class TPSProcessor { try { tks = new TKSRemoteRequestHandler(connId, getSelectedKeySet()); - data = tks.encryptData(appletInfo.getKDD(),appletInfo.getCUID(), keyInfo, plaintextChallenge); + data = tks.encryptData(appletInfo.getKDD(),appletInfo.getCUID(), keyInfo, plaintextChallenge,protocol); } catch (EBaseException e) { throw new TPSException("TPSProcessor.encryptData: Erorr getting wrapped data from TKS!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL); @@ -482,7 +486,9 @@ public class TPSProcessor { protected TPSBuffer initializeUpdate(byte keyVersion, byte keyIndex, TPSBuffer randomData) throws IOException, TPSException { - CMS.debug("In TPS_Processor.initializeUpdate."); + String method = "TPSProcessor.initializeUpdate:"; + + CMS.debug(method + " Entering..."); InitializeUpdateAPDU initUpdate = new InitializeUpdateAPDU(keyVersion, keyIndex, randomData); int done = 0; @@ -500,7 +506,10 @@ public class TPSProcessor { TPSBuffer data = resp.getResultDataNoCode(); - if (data.size() != INIT_UPDATE_DATA_SIZE) { + CMS.debug(method + " data.size() " + data.size()); + + if ((data.size() != INIT_UPDATE_DATA_SIZE) && (data.size() != INIT_UPDATE_DATA_SIZE_02) + && (data.size() != INIT_UPDATE_DATA_SIZE_03)) { throw new TPSException("TPSBuffer.initializeUpdate: Invalid response from token!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL); } @@ -550,12 +559,22 @@ public class TPSProcessor { TPSBuffer initUpdateResp = initializeUpdate(keyVersion, keyIndex, randomData); + CMS.debug("TPSProcessor.setupSecureChanne: initUpdateResponse: " + initUpdateResp.toHexString()); + TPSBuffer key_diversification_data = initUpdateResp.substr(0, DIVERSIFICATION_DATA_SIZE); appletInfo.setKDD(key_diversification_data); CMS.debug("TPSProcessor.setupSecureChannel: diversification data: " + key_diversification_data.toHexString()); - TPSBuffer key_info_data = initUpdateResp.substr(DIVERSIFICATION_DATA_SIZE, 2); + TPSBuffer key_info_data = null; + + if (platProtInfo.isSCP03()) { + key_info_data = initUpdateResp.substr(DIVERSIFICATION_DATA_SIZE, 3); + } else { + key_info_data = initUpdateResp.substr(DIVERSIFICATION_DATA_SIZE, 2); + } + + CMS.debug("TPSProcessor.setupSecureChannel: key info data: " + key_info_data.toHexString()); TokenRecord tokenRecord = getTokenRecord(); @@ -564,19 +583,13 @@ public class TPSProcessor { TPSBuffer card_cryptogram = null; TPSBuffer sequenceCounter = null; - boolean isGp211scp02 = false; - - if (platProtInfo.getPlatform().equals(SecureChannel.GP211)) { - isGp211scp02 = true; - } - card_cryptogram = initUpdateResp.substr(CARD_CRYPTOGRAM_OFFSET, CARD_CRYPTOGRAM_SIZE); //CMS.debug("TPSProcessor.setupSecureChannel: card cryptogram: " + card_cryptogram.toHexString()); CMS.debug("TPSProcessor.setupSecureChannel: card cryptogram: extracted"); TPSBuffer card_challenge = null; - if (isGp211scp02) { + if (platProtInfo.isSCP02()) { sequenceCounter = initUpdateResp.substr(SEQUENCE_COUNTER_OFFSET_GP211_SC02, 2); { @@ -602,7 +615,15 @@ public class TPSProcessor { tokenRecord.setKeyInfo(key_info_data.toHexStringPlain()); + } else if (platProtInfo.isSCP03()) { + card_challenge = initUpdateResp.substr(CARD_CHALLENGE_OFFSET_GP211_SC03,CARD_CHALLENGE_SIZE); + card_cryptogram = initUpdateResp.substr(CARD_CRYPTOGRAM_OFFSET_GP211_SC03, CARD_CRYPTOGRAM_SIZE); + + CMS.debug("TPSProcessor.setupSecureChannel 03: card cryptogram: " + card_cryptogram.toHexString()); + CMS.debug("TPSProcessor.setupSecureChannel 03: card challenge: " + card_challenge.toHexString()); + CMS.debug("TPSProcessor.setupSecureChannel 03: host challenge: " + randomData.toHexString()); } else { + card_challenge = initUpdateResp.substr(CARD_CHALLENGE_OFFSET, CARD_CHALLENGE_SIZE); } //CMS.debug("TPSProcessor.setupSecureChannel: card challenge: " + card_challenge.toHexString()); @@ -628,6 +649,8 @@ public class TPSProcessor { TPSBuffer sequenceCounter,AppletInfo appletInfo) throws EBaseException, TPSException, IOException { + String method = "TPSProcessor.generateSecureChannel:"; + if (connId == null || keyDiversificationData == null || keyInfoData == null || cardChallenge == null || cardCryptogram == null || hostChallenge == null || appletInfo == null) { throw new TPSException("TPSProcessor.generateSecureChannel: Invalid input data!", @@ -654,6 +677,11 @@ public class TPSProcessor { PK11SymKey cmacSessionKeySCP02 = null; PK11SymKey rmacSessionKeySCP02 = null; + PK11SymKey encSessionKeySCP03 = null; + PK11SymKey macSessionKeySCP03 = null; + PK11SymKey kekSessionKeySCP03 = null; + PK11SymKey rmacSessionKeySCP03 = null; + SymmetricKey sharedSecret = null; //Sanity checking @@ -680,7 +708,14 @@ public class TPSProcessor { TPSStatus.STATUS_ERROR_SECURE_CHANNEL); } - SecureChannelProtocol protocol = new SecureChannelProtocol(); + SecureChannelProtocol protocol = null; //new SecureChannelProtocol(); + + + if(platProtInfo.isSCP01() || platProtInfo.isSCP02() ) { + protocol = new SecureChannelProtocol(1); + } else if (platProtInfo.isSCP03()) { + protocol = new SecureChannelProtocol(3); + } String tokenName = CryptoUtil.INTERNAL_TOKEN_FULL_NAME; @@ -715,7 +750,6 @@ public class TPSProcessor { if (hostCryptogram == null) { throw new TPSException("TPSProcessor.generateSecureChannel: No host cryptogram returned from token!", TPSStatus.STATUS_ERROR_SECURE_CHANNEL); - } try { @@ -725,9 +759,7 @@ public class TPSProcessor { /* sessionKey = SessionKey.UnwrapSessionKeyWithSharedSecret(tokenName, (PK11SymKey) sharedSecret, sessionKeyWrapped.toBytesArray()); */ - - sessionKey = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, sessionKeyWrapped.toBytesArray(), false); - + sessionKey = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, sessionKeyWrapped.toBytesArray(), false,SymmetricKey.DES3); if (sessionKey == null) { CMS.debug("TPSProcessor.generateSecureChannel: Can't extract session key!"); @@ -740,7 +772,7 @@ public class TPSProcessor { /* encSessionKey = SessionKey.UnwrapSessionKeyWithSharedSecret(tokenName,(PK11SymKey) sharedSecret, encSessionKeyWrapped.toBytesArray()); */ - encSessionKey = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret,encSessionKeyWrapped.toBytesArray(),false); + encSessionKey = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret,encSessionKeyWrapped.toBytesArray(),false,SymmetricKey.DES3); if (encSessionKey == null) { CMS.debug("TPSProcessor.generateSecureChannel: Can't extract enc session key!"); @@ -781,7 +813,7 @@ public class TPSProcessor { } - if (platProtInfo.isGP211() && platProtInfo.isSCP02()) { + if (platProtInfo.isSCP02()) { //Generate the 4 keys we need for SCP02, Impl 15 if (sequenceCounter == null) { @@ -805,8 +837,8 @@ public class TPSProcessor { } respCMac02 = engine.computeSessionKeySCP02(keyDiversificationData, appletInfo.getCUID(), keyInfoData, - sequenceCounter, new TPSBuffer(SecureChannel.C_MACDerivationConstant), - connId, getSelectedTokenType(), getSelectedKeySet()); + sequenceCounter, new TPSBuffer(SecureChannel.C_MACDerivationConstant), connId, + getSelectedTokenType(), getSelectedKeySet()); TPSBuffer cmacSessionKeyWrappedSCP02 = respCMac02.getSessionKey(); @@ -875,6 +907,43 @@ public class TPSProcessor { } + if (platProtInfo.isSCP03()) { + CMS.debug("TPSProcessor.generateSecureChannel Trying secure channel protocol 03"); + + resp = engine.computeSessionKeysSCP03(keyDiversificationData, appletInfo.getCUID(), keyInfoData, + cardChallenge, hostChallenge, cardCryptogram, connId, getSelectedTokenType(), getSelectedKeySet()); + + TPSBuffer encSessionKeyBuff = resp.getEncSessionKey(); + TPSBuffer kekSessionKeyBuff = resp.getKekSessionKey(); + TPSBuffer macSessionKeyBuff = resp.getMacSessionKey(); + TPSBuffer hostCryptogramBuff = resp.getHostCryptogram(); + TPSBuffer keyCheckBuff = resp.getKeyCheck(); + + TPSBuffer drmDesKeyBuff = resp.getDRM_Trans_DesKey(); + TPSBuffer kekDesKeyBuff = resp.getKekWrappedDesKey(); + + CMS.debug(method + " encSessionKeyBuff: " + encSessionKeyBuff.toHexString()); + CMS.debug(method + " kekSessionKeyBuff: " + kekSessionKeyBuff.toHexString()); + CMS.debug(method + " macSessionKeyBuff: " + macSessionKeyBuff.toHexString()); + CMS.debug(method + " hostCryptogramBuff: " + hostCryptogramBuff.toHexString()); + CMS.debug(method + " keyCheckBuff: " + keyCheckBuff.toHexString()); + CMS.debug(method + " drmDessKeyBuff: " + drmDesKeyBuff.toHexString()); + CMS.debug(method + " kekDesKeyBuff: " + kekDesKeyBuff.toHexString()); + + encSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + encSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + macSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + macSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + kekSessionKeySCP03 = (PK11SymKey) protocol.unwrapWrappedSymKeyOnToken(token, sharedSecret, + kekSessionKeyBuff.toBytesArray(), false, SymmetricKey.AES); + + channel = new SecureChannel(this, encSessionKeySCP03, macSessionKeySCP03, kekSessionKeySCP03, + drmDesKeyBuff, kekDesKeyBuff, + keyCheckBuff, keyDiversificationData, cardChallenge, + cardCryptogram, hostChallenge, hostCryptogramBuff, keyInfoData, + platProtInfo); + } + if (channel == null) { throw new TPSException( "TPSProcessor.generateSecureChannel: Can't create Secure Channel, possibly invalid secure channel protocol requested.", @@ -3141,9 +3210,6 @@ public class TPSProcessor { The second byte is the key offset, which is always 1 */ - byte[] nv = { (byte) requiredVersion, 0x01 }; - TPSBuffer newVersion = new TPSBuffer(nv); - // GetKeyInfoData will return a buffer which is bytes 11,12 of // the data structure on page 89 of Cyberflex Access Programmer's // Guide @@ -3157,8 +3223,21 @@ public class TPSProcessor { int protocol = 1; if (channel.isSCP02()) { protocol = 2; + } if (channel.isSCP03()) { + protocol = 3; } + byte[] nv = null; + + if(protocol == 3) { + nv = new byte[] { (byte) requiredVersion,curKeyInfo.at(1),curKeyInfo.at(2) }; + + } else { + nv = new byte[] { (byte) requiredVersion, 0x01 }; + } + + TPSBuffer newVersion = new TPSBuffer(nv); + //Sanity checking boolean cuidOK = checkCUIDMatchesKDD(appletInfo.getCUIDhexStringPlain(), appletInfo.getKDDhexStringPlain()); @@ -3574,14 +3653,21 @@ public class TPSProcessor { try { gp211GetSecureChannelProtocolDetails(); } catch (TPSException e) { + + if(platProtInfo.getProtocol() == SecureChannel.SECURE_PROTO_03) { + CMS.debug("PSProcessor.acquireChannelPlatformProtocolInfo: card is reporting SCP03, bail, we don't yet support!"); + throw e; + } + CMS.debug("TPSProcessor.acquireChannelPlatformProtocolInfo: Error getting gp211 protocol data, assume scp01 " + e); + platProtInfo.setPlatform(SecureChannel.GP201); platProtInfo.setProtocol(SecureChannel.SECURE_PROTO_01); } - if (platProtInfo.isGP211() && platProtInfo.isSCP02()) { + if (platProtInfo.isSCP02()) { // We only support impl 15, the most common, at this point. if (platProtInfo.getImplementation() != SecureChannel.GP211_SCP02_IMPL_15) { @@ -3690,16 +3776,17 @@ public class TPSProcessor { byte protocol = oidSecureChannelProtocol.at(length - 2); byte implementation = oidSecureChannelProtocol.at(length - 1); - if (protocol == SecureChannel.SECURE_PROTO_03) { - throw new TPSException("TPSProcessor.gp211GetSecureChannelProtocolDetails: No support for SCP03 as of yet, bailing.", - TPSStatus.STATUS_ERROR_SECURE_CHANNEL); - } + platProtInfo.setProtocol(protocol); platProtInfo.setImplementation(implementation); platProtInfo.setKeysetInfoData(keyData); - if (protocol == SecureChannel.SECURE_PROTO_02) + if (protocol == SecureChannel.SECURE_PROTO_03) { + CMS.debug("TPSProcessor.gp211GetSecureChannelProtocolDetails: Found protocol 03!"); + } + + if ((protocol == SecureChannel.SECURE_PROTO_02) || (protocol == SecureChannel.SECURE_PROTO_03)) platProtInfo.setPlatform(SecureChannel.GP211); else platProtInfo.setPlatform(SecureChannel.GP201); @@ -3714,6 +3801,12 @@ public class TPSProcessor { return platProtInfo; } + public int getProtocol() { + if(platProtInfo == null) + return SecureChannel.SECURE_PROTO_01; + return platProtInfo.getProtocol(); + } + boolean checkCardGPKeyVersionIsInRange(String CUID, String KDD, String keyInfoData) throws TPSException { boolean result = true; @@ -3772,11 +3865,14 @@ public class TPSProcessor { CMS.debug(method + " minVersion: " + minVersion + " maxVersion: " + maxVersion); - if (keyInfoData.length() != 4) { + if( keyInfoData.length() != 4 && keyInfoData.length() != 6) { result = false; } else { + + // Actually check the version range; + String keyInfoVer = keyInfoData.substring(0, 2); CMS.debug(method + " Version reported from key Info Data: " + keyInfoVer); diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java index 57119ce2c..de1ac442c 100644 --- a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java +++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java @@ -19,7 +19,6 @@ package com.netscape.cmsutil.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.CharConversionException; import java.io.FilterOutputStream; import java.io.IOException; import java.io.PrintStream; @@ -1614,25 +1613,18 @@ public class CryptoUtil { } } - /** - * Generates a symmetric key. - */ - public static SymmetricKey generateKey(CryptoToken token, - KeyGenAlgorithm alg, int keySize) - throws TokenException, NoSuchAlgorithmException, - IllegalStateException, InvalidAlgorithmParameterException { - try { - KeyGenerator kg = token.getKeyGenerator(alg); - if (alg == KeyGenAlgorithm.AES || alg == KeyGenAlgorithm.RC4 - || alg == KeyGenAlgorithm.RC2) { - kg.initialize(keySize); - } - - return kg.generate(); - } catch (CharConversionException e) { - throw new RuntimeException( - "CharConversionException while generating symmetric key"); + public static SymmetricKey generateKey(CryptoToken token, KeyGenAlgorithm alg, int keySize, + SymmetricKey.Usage[] usages, boolean temporary) throws Exception { + KeyGenerator kg = token.getKeyGenerator(alg); + if (usages != null) + kg.setKeyUsages(usages); + kg.temporaryKeys(temporary); + if (alg == KeyGenAlgorithm.AES || alg == KeyGenAlgorithm.RC4 + || alg == KeyGenAlgorithm.RC2) { + kg.initialize(keySize); } + + return kg.generate(); } /** @@ -1908,18 +1900,6 @@ public class CryptoUtil { return decodedData; } - public static byte[] unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey, - SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException, - BadPaddingException, - IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException { - - Cipher decryptor = token.getCipherContext(alg); - decryptor.initDecrypt(recoveryKey, IV); - byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey); - - return unwrappedData; - } - public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException, InvalidKeyException, @@ -1940,56 +1920,25 @@ public class CryptoUtil { } public static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert, - SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException, - InvalidKeyException, InvalidAlgorithmParameterException { + SymmetricKey sk) throws Exception { byte transport[] = Utils.base64decode(transportCert); X509Certificate tcert = manager.importCACertPackage(transport); - KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA); - rsaWrap.initWrap(tcert.getPublicKey(), null); - byte session_data[] = rsaWrap.wrap(sk); - return session_data; - } - - /** - * Wrap a symmetric Key with a SymmetricKey - * - * @param token - * @param secret - * @param wrapper - * @return - * @throws TokenException - * @throws NoSuchAlgorithmException - * @throws InvalidAlgorithmParameterException - * @throws InvalidKeyException - */ - public static byte[] wrapSymmetricKey(CryptoToken token, SymmetricKey secret, SymmetricKey wrapper, - IVParameterSpec IV) throws NoSuchAlgorithmException, TokenException, InvalidKeyException, - InvalidAlgorithmParameterException { - KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper1.initWrap(wrapper, IV); - byte[] keyData = wrapper1.wrap(secret); - - return keyData; + return wrapUsingPublicKey(token, tcert.getPublicKey(), sk, KeyWrapAlgorithm.RSA); } public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert, - SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) throws TokenException, - CharConversionException, - NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, - CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException, - BadPaddingException, InvalidBERException { + SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) + throws Exception { byte[] key_data = null; //generate session key - SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg, symKeySize); + SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg, symKeySize, null, false); if (passphrase != null) { key_data = wrapPassphrase(token, passphrase, IV, sk, EncryptionAlgorithm.DES3_CBC_PAD); } else { // wrap payload using session key - KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper1.initWrap(sk, IV); - key_data = wrapper1.wrap(vek); + key_data = wrapUsingSymmetricKey(token, sk, vek, IV, KeyWrapAlgorithm.DES3_CBC_PAD); } // wrap session key using transport key @@ -2001,19 +1950,11 @@ public class CryptoUtil { public static byte[] createPKIArchiveOptions( CryptoToken token, PublicKey wrappingKey, PrivateKey toBeWrapped, KeyGenAlgorithm keyGenAlg, int symKeySize, IVParameterSpec IV) - throws TokenException, NoSuchAlgorithmException, - InvalidAlgorithmParameterException, InvalidKeyException, - IOException, InvalidBERException { - SymmetricKey sessionKey = CryptoUtil.generateKey(token, keyGenAlg, symKeySize); - - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initWrap(sessionKey, IV); - byte[] key_data = wrapper.wrap(toBeWrapped); - - wrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA); - wrapper.initWrap(wrappingKey, null); - byte session_data[] = wrapper.wrap(sessionKey); + throws Exception { + SymmetricKey sessionKey = CryptoUtil.generateKey(token, keyGenAlg, symKeySize, null, false); + byte[] key_data = wrapUsingSymmetricKey(token, sessionKey, toBeWrapped, IV, KeyWrapAlgorithm.DES3_CBC_PAD); + byte[] session_data = wrapUsingPublicKey(token, wrappingKey, sessionKey, KeyWrapAlgorithm.RSA); return createPKIArchiveOptions(IV, session_data, key_data); } @@ -2050,30 +1991,22 @@ public class CryptoUtil { PublicKey pubkey, byte[] data) throws InvalidBERException, Exception { ByteArrayInputStream in = new ByteArrayInputStream(data); - PKIArchiveOptions options = (PKIArchiveOptions) - (new PKIArchiveOptions.Template()).decode(in); + PKIArchiveOptions options = (PKIArchiveOptions) (new PKIArchiveOptions.Template()).decode(in); EncryptedKey encKey = options.getEncryptedKey(); EncryptedValue encVal = encKey.getEncryptedValue(); AlgorithmIdentifier algId = encVal.getSymmAlg(); BIT_STRING encSymKey = encVal.getEncSymmKey(); BIT_STRING encPrivKey = encVal.getEncValue(); - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.RSA); - wrapper.initUnwrap(unwrappingKey, null); - SymmetricKey sk = wrapper.unwrapSymmetric( - encSymKey.getBits(), SymmetricKey.Type.DES3, 0); + SymmetricKey sk = unwrap(token, SymmetricKey.Type.DES3, 0, null, unwrappingKey, encSymKey.getBits(), + KeyWrapAlgorithm.RSA); ASN1Value v = algId.getParameters(); v = ((ANY) v).decodeWith(new OCTET_STRING.Template()); byte iv[] = ((OCTET_STRING) v).toByteArray(); IVParameterSpec ivps = new IVParameterSpec(iv); - wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); - wrapper.initUnwrap(sk, ivps); - PrivateKey.Type keyType = pubkey.getAlgorithm().equals("EC") - ? PrivateKey.Type.EC - : PrivateKey.Type.RSA; - return wrapper.unwrapPrivate(encPrivKey.getBits(), keyType, pubkey); + return unwrap(token, pubkey, false, sk, encPrivKey.getBits(), KeyWrapAlgorithm.DES3_CBC_PAD, ivps); } public static boolean sharedSecretExists(String nickname) throws NotInitializedException, TokenException { @@ -2098,22 +2031,22 @@ public class CryptoUtil { km.deleteUniqueNamedKey(nickname); } - // Return a list of two wrapped keys: first element: temp DES3 key wrapped by cert , second element: shared secret wrapped by temp DES3 key - public static List<byte[]> exportSharedSecret(String nickname, java.security.cert.X509Certificate wrappingCert,SymmetricKey wrappingKey) - throws NotInitializedException, TokenException, IOException, NoSuchAlgorithmException, InvalidKeyException, - InvalidAlgorithmParameterException, InvalidKeyFormatException { + // Return a list of two wrapped keys: + // first element: temp DES3 key wrapped by cert , + // second element: shared secret wrapped by temp DES3 key + public static List<byte[]> exportSharedSecret(String nickname, java.security.cert.X509Certificate wrappingCert, + SymmetricKey wrappingKey) throws Exception { CryptoManager cm = CryptoManager.getInstance(); CryptoToken token = cm.getInternalKeyStorageToken(); List<byte[]> listWrappedKeys = new ArrayList<byte[]>(); - KeyManager km = new KeyManager(token); if (!km.uniqueNamedKeyExists(nickname)) { throw new IOException("Shared secret " + nickname + " does not exist"); } - SymmetricKey sharedSecretKey = null; + SymmetricKey sharedSecretKey = null; try { sharedSecretKey = getSymKeyByName(token, nickname); @@ -2125,25 +2058,18 @@ public class CryptoUtil { throw new IOException("Shared secret " + nickname + " does not exist"); } - KeyWrapper keyWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA); PublicKey pub = wrappingCert.getPublicKey(); PK11PubKey pubK = PK11PubKey.fromSPKI(pub.getEncoded()); - keyWrap.initWrap(pubK, null); //Wrap the temp DES3 key with the cert - byte[] wrappedKey = keyWrap.wrap(wrappingKey); - + byte[] wrappedKey = wrapUsingPublicKey(token, pubK, wrappingKey, KeyWrapAlgorithm.RSA); listWrappedKeys.add(wrappedKey); //Use the DES3 key to wrap the shared secret - KeyWrapper keyWrapSharedSecret = token.getKeyWrapper(KeyWrapAlgorithm.DES3_ECB); - keyWrapSharedSecret.initWrap(wrappingKey,null); - - byte[] wrappedSharedSecret = keyWrapSharedSecret.wrap(sharedSecretKey); - + byte[] wrappedSharedSecret = wrapUsingSymmetricKey(token, wrappingKey, sharedSecretKey, null, KeyWrapAlgorithm.DES3_ECB); listWrappedKeys.add(wrappedSharedSecret); - if(listWrappedKeys.size() != 2) { + if (listWrappedKeys.size() != 2) { throw new IOException("Can't write out shared secret data to export for nickname: " + nickname); } @@ -2236,6 +2162,90 @@ public class CryptoUtil { return vect; } + + ////////////////////////////////////////////////////////////////////////////////////////////// + //generic crypto operations + ////////////////////////////////////////////////////////////////////////////////////////////// + + public static byte[] decryptUsingSymmetricKey(CryptoToken token, IVParameterSpec ivspec, byte[] encryptedData, + SymmetricKey wrappingKey, EncryptionAlgorithm encryptionAlgorithm) throws Exception { + Cipher decryptor = token.getCipherContext(encryptionAlgorithm); + decryptor.initDecrypt(wrappingKey, ivspec); + return decryptor.doFinal(encryptedData); + } + + public static byte[] encryptUsingSymmetricKey(CryptoToken token, SymmetricKey wrappingKey, byte[] data, + EncryptionAlgorithm alg, IVParameterSpec ivspec) + throws Exception { + Cipher cipher = token.getCipherContext(alg); + cipher.initEncrypt(wrappingKey, ivspec); + return cipher.doFinal(data); + } + + public static byte[] wrapUsingSymmetricKey(CryptoToken token, SymmetricKey wrappingKey, SymmetricKey data, + IVParameterSpec ivspec, KeyWrapAlgorithm alg) throws Exception { + KeyWrapper wrapper = token.getKeyWrapper(alg); + wrapper.initWrap(wrappingKey, ivspec); + return wrapper.wrap(data); + } + + public static byte[] wrapUsingSymmetricKey(CryptoToken token, SymmetricKey wrappingKey, PrivateKey data, + IVParameterSpec ivspec, KeyWrapAlgorithm alg) throws Exception { + KeyWrapper wrapper = token.getKeyWrapper(alg); + wrapper.initWrap(wrappingKey, ivspec); + return wrapper.wrap(data); + } + + public static byte[] wrapUsingPublicKey(CryptoToken token, PublicKey wrappingKey, SymmetricKey data, + KeyWrapAlgorithm alg) throws Exception { + KeyWrapper rsaWrap = token.getKeyWrapper(alg); + rsaWrap.initWrap(wrappingKey, null); + return rsaWrap.wrap(data); + } + + public static SymmetricKey unwrap(CryptoToken token, SymmetricKey.Type keyType, + int strength, SymmetricKey.Usage usage, SymmetricKey wrappingKey, byte[] wrappedData, + KeyWrapAlgorithm wrapAlgorithm, IVParameterSpec wrappingIV) throws Exception { + KeyWrapper wrapper = token.getKeyWrapper(wrapAlgorithm); + wrapper.initUnwrap(wrappingKey, wrappingIV); + return wrapper.unwrapSymmetric(wrappedData, keyType, usage, strength); + } + + public static SymmetricKey unwrap(CryptoToken token, SymmetricKey.Type keyType, + int strength, SymmetricKey.Usage usage, PrivateKey wrappingKey, byte[] wrappedData, + KeyWrapAlgorithm wrapAlgorithm) throws Exception { + KeyWrapper keyWrapper = token.getKeyWrapper(wrapAlgorithm); + keyWrapper.initUnwrap(wrappingKey, null); + + return keyWrapper.unwrapSymmetric(wrappedData, keyType, usage, strength); + } + + public static PrivateKey unwrap(CryptoToken token, PublicKey pubKey, boolean temporary, + SymmetricKey wrappingKey, byte[] wrappedData, KeyWrapAlgorithm wrapAlgorithm, IVParameterSpec wrapIV) + throws Exception { + KeyWrapper wrapper = token.getKeyWrapper(wrapAlgorithm); + wrapper.initUnwrap(wrappingKey, wrapIV); + + // Get the key type for unwrapping the private key. + PrivateKey.Type keyType = null; + if (pubKey.getAlgorithm().equalsIgnoreCase("RSA")) { + keyType = PrivateKey.RSA; + } else if (pubKey.getAlgorithm().equalsIgnoreCase("DSA")) { + keyType = PrivateKey.DSA; + } else if (pubKey.getAlgorithm().equalsIgnoreCase("EC")) { + keyType = PrivateKey.EC; + } + + PrivateKey pk = null; + if (temporary) { + pk = wrapper.unwrapTemporaryPrivate(wrappedData, + keyType, pubKey); + } else { + pk = wrapper.unwrapPrivate(wrappedData, + keyType, pubKey); + } + return pk; + } } // START ENABLE_ECC diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java index 9adb62972..0b164aafc 100644 --- a/base/util/src/netscape/security/pkcs/PKCS12Util.java +++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java @@ -47,7 +47,6 @@ import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.IVParameterSpec; import org.mozilla.jss.crypto.InternalCertificate; import org.mozilla.jss.crypto.KeyGenAlgorithm; -import org.mozilla.jss.crypto.KeyGenerator; import org.mozilla.jss.crypto.KeyWrapAlgorithm; import org.mozilla.jss.crypto.KeyWrapper; import org.mozilla.jss.crypto.NoSuchItemOnTokenException; @@ -68,6 +67,8 @@ import org.mozilla.jss.util.Password; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.netscape.cmsutil.crypto.CryptoUtil; + import netscape.ldap.LDAPDN; import netscape.ldap.util.DN; import netscape.security.x509.X509CertImpl; @@ -114,18 +115,19 @@ public class PKCS12Util { } byte[] getEncodedKey(PrivateKey privateKey) throws Exception { - CryptoManager cm = CryptoManager.getInstance(); CryptoToken token = cm.getInternalKeyStorageToken(); - KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3); - SymmetricKey sk = kg.generate(); - - KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); byte[] iv = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; IVParameterSpec param = new IVParameterSpec(iv); - wrapper.initWrap(sk, param); - byte[] enckey = wrapper.wrap(privateKey); + + SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); + byte[] enckey = CryptoUtil.wrapUsingSymmetricKey( + token, + sk, + privateKey, + param, + KeyWrapAlgorithm.DES3_CBC_PAD); Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); c.initDecrypt(sk, param); @@ -592,6 +594,9 @@ public class PKCS12Util { logger.debug("Importing private key " + keyInfo.subjectDN); + byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; + IVParameterSpec param = new IVParameterSpec(iv); + PrivateKeyInfo privateKeyInfo = keyInfo.privateKeyInfo; // encode private key @@ -622,13 +627,9 @@ public class PKCS12Util { } // encrypt private key - KeyGenerator kg = token.getKeyGenerator(KeyGenAlgorithm.DES3); - SymmetricKey sk = kg.generate(); - byte iv[] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; - IVParameterSpec param = new IVParameterSpec(iv); - Cipher c = token.getCipherContext(EncryptionAlgorithm.DES3_CBC_PAD); - c.initEncrypt(sk, param); - byte[] encpkey = c.doFinal(privateKey); + SymmetricKey sk = CryptoUtil.generateKey(token, KeyGenAlgorithm.DES3, 0, null, true); + byte[] encpkey = CryptoUtil.encryptUsingSymmetricKey( + token, sk, privateKey, EncryptionAlgorithm.DES3_CBC_PAD, param); // unwrap private key to load into database KeyWrapper wrapper = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD); diff --git a/pylint-build-scan.py b/pylint-build-scan.py index d4156e87b..3a7b47321 100755 --- a/pylint-build-scan.py +++ b/pylint-build-scan.py @@ -38,7 +38,6 @@ PYLINTRC = os.path.join(SCRIPTPATH, 'dogtag.pylintrc') FILENAMES = [ os.path.abspath(__file__), '{sitepackages}/pki', - '{bin}/pki-cmd', # see HACK '{sbin}/pkispawn', '{sbin}/pkidestroy', '{sbin}/pki-upgrade', @@ -130,17 +129,7 @@ def main(): if args.verbose: pprint.pprint(pylint) - # HACK: - # pylint confuses the pki command with the pki package. We create a - # symlink from bin/pki to bin/pki-cmd and test bin/pki-cmd instead. - pki_bin = '{bin}/pki'.format(**env) - pki_cmd = '{bin}/pki-cmd'.format(**env) - os.symlink(pki_bin, pki_cmd) - - try: - return subprocess.call(pylint, cwd=env['sitepackages']) - finally: - os.unlink(pki_cmd) + return subprocess.call(pylint, cwd=env['sitepackages']) if __name__ == '__main__': sys.exit(main()) diff --git a/specs/dogtag-pki-theme.spec b/specs/dogtag-pki-theme.spec index f87c1b578..12b73702a 100644 --- a/specs/dogtag-pki-theme.spec +++ b/specs/dogtag-pki-theme.spec @@ -1,6 +1,6 @@ Name: dogtag-pki-theme Version: 10.4.0 -Release: 0.1%{?dist} +Release: 1%{?dist} Summary: Certificate System - Dogtag PKI Theme Components URL: http://pki.fedoraproject.org/ License: GPLv2 @@ -168,6 +168,9 @@ cd build %changelog +* Tue Mar 14 2017 Dogtag Team <pki-devel@redhat.com> 10.4.0-1 +- dogtagpki Pagure Issue #2541 - Re-base Dogtag pki packages to 10.4.x + * Mon Aug 8 2016 Dogtag Team <pki-devel@redhat.com> 10.4.0-0.1 - Updated version number to 10.4.0-0.1 diff --git a/specs/dogtag-pki.spec b/specs/dogtag-pki.spec index 040ca0151..4e0b13d47 100644 --- a/specs/dogtag-pki.spec +++ b/specs/dogtag-pki.spec @@ -7,7 +7,7 @@ Summary: Dogtag Public Key Infrastructure (PKI) Suite Name: dogtag-pki Version: 10.4.0 -Release: 0.1%{?dist} +Release: 1%{?dist} # The entire source code is GPLv2 except for 'pki-tps' which is LGPLv2 License: GPLv2 and LGPLv2 URL: http://pki.fedoraproject.org/ @@ -19,7 +19,7 @@ BuildArch: noarch %define esc_version 1.1.0 # NOTE: The following package versions are TLS compliant: %if 0%{?rhel} -%define pki_core_rhel_version 10.3.3 +%define pki_core_rhel_version 10.4.0 %define pki_core_rhcs_version %{version} %else %define pki_core_version %{version} @@ -124,6 +124,9 @@ rm -rf %{buildroot} %doc README %changelog +* Tue Mar 14 2017 Dogtag Team <pki-devel@redhat.com> 10.4.0-1 +- dogtagpki Pagure Issue #2541 - Re-base Dogtag pki packages to 10.4.x + * Mon Aug 8 2016 Dogtag Team <pki-devel@redhat.com> 10.4.0-0.1 - Updated version number to 10.4.0-0.1 diff --git a/specs/pki-console.spec b/specs/pki-console.spec index 6a6a282e5..86c3f2d0e 100644 --- a/specs/pki-console.spec +++ b/specs/pki-console.spec @@ -1,6 +1,6 @@ Name: pki-console Version: 10.4.0 -Release: 0.1%{?dist} +Release: 1%{?dist} Summary: Certificate System - PKI Console URL: http://pki.fedoraproject.org/ License: GPLv2 @@ -9,7 +9,7 @@ Group: System Environment/Base %bcond_without javadoc %if 0%{?rhel} -%define pki_core_rhel_version 10.3.3 +%define pki_core_rhel_version 10.4.0 %define pki_core_version %{pki_core_rhel_version} %else %define pki_core_version %{version} @@ -27,7 +27,7 @@ BuildRequires: nspr-devel BuildRequires: nss-devel BuildRequires: junit BuildRequires: jpackage-utils >= 1.7.5-10 -BuildRequires: jss >= 4.2.6-40 +BuildRequires: jss >= 4.4.0-1 BuildRequires: pki-base-java >= %{pki_core_version} Requires: idm-console-framework @@ -36,7 +36,7 @@ Requires: ldapjdk Requires: pki-base-java >= %{pki_core_version} Requires: pki-console-theme >= %{version} Requires: jpackage-utils >= 1.7.5-10 -Requires: jss >= 4.2.6-40 +Requires: jss >= 4.4.0-1 %if 0%{?rhel} # NOTE: In the future, as a part of its path, this URL will contain a release @@ -98,6 +98,10 @@ cd build %changelog +* Tue Mar 14 2017 Dogtag Team <pki-devel@redhat.com> 10.4.0-1 +- Require "jss >= 4.4.0-1" as a build and runtime requirement +- dogtagpki Pagure Issue #2541 - Re-base Dogtag pki packages to 10.4.x + * Mon Aug 8 2016 Dogtag Team <pki-devel@redhat.com> 10.4.0-0.1 - Updated version number to 10.4.0-0.1 diff --git a/specs/pki-core.spec b/specs/pki-core.spec index 39911af41..2ef46e28d 100644 --- a/specs/pki-core.spec +++ b/specs/pki-core.spec @@ -13,7 +13,7 @@ %global package_rhel_packages 1 # Package RHCS-specific RPMS Only %global package_rhcs_packages 1 -%define pki_core_rhel_version 10.3.3 +%define pki_core_rhel_version 10.4.0 %else # 0%{?fedora} # Fedora always packages all RPMS @@ -65,7 +65,7 @@ Name: pki-core Version: 10.4.0 -Release: 0.1%{?dist} +Release: 1%{?dist} Summary: Certificate System - PKI Core Components URL: http://pki.fedoraproject.org/ License: GPLv2 @@ -170,16 +170,16 @@ BuildRequires: policycoreutils-python-utils BuildRequires: python-ldap BuildRequires: junit BuildRequires: jpackage-utils >= 0:1.7.5-10 -BuildRequires: jss >= 4.2.6-40 +BuildRequires: jss >= 4.4.0-1 BuildRequires: systemd-units %if 0%{?rhel} -BuildRequires: tomcatjss >= 7.1.2-2 +BuildRequires: tomcatjss >= 7.2.1-1 %else %if 0%{?fedora} >= 23 -BuildRequires: tomcatjss >= 7.1.3 +BuildRequires: tomcatjss >= 7.2.1-1 %else -BuildRequires: tomcatjss >= 7.1.2-2 +BuildRequires: tomcatjss >= 7.1.3 %endif %endif @@ -318,7 +318,7 @@ Requires: nss >= 3.14.3 %endif Requires: jpackage-utils >= 0:1.7.5-10 -Requires: jss >= 4.2.6-40 +Requires: jss >= 4.4.0-1 Provides: symkey = %{version}-%{release} @@ -400,7 +400,7 @@ Requires: slf4j-jdk14 %endif Requires: javassist Requires: jpackage-utils >= 0:1.7.5-10 -Requires: jss >= 4.2.6-40 +Requires: jss >= 4.4.0-1 Requires: ldapjdk Requires: pki-base = %{version}-%{release} @@ -583,12 +583,12 @@ Requires(postun): systemd-units Requires(pre): shadow-utils %if 0%{?rhel} -Requires: tomcatjss >= 7.1.2-2 +Requires: tomcatjss >= 7.2.1-1 %else %if 0%{?fedora} >= 23 -Requires: tomcatjss >= 7.1.3 +Requires: tomcatjss >= 7.2.1-1 %else -Requires: tomcatjss >= 7.1.2-2 +Requires: tomcatjss >= 7.1.3 %endif %endif @@ -1347,17 +1347,297 @@ systemctl daemon-reload %endif # %{with server} %changelog -* Mon Aug 8 2016 Dogtag Team <pki-devel@redhat.com> 10.4.0-0.1 +* Tue Mar 14 2017 Dogtag Team <pki-devel@redhat.com> 10.4.0-1 +- Require "jss >= 4.4.0-1" as a build and runtime requirement +- Require "tomcatjss >= 7.2.1-1" as a build and runtime requirement +- ############################################################################ +- dogtagpki Pagure Issue #2541 - Re-base Dogtag pki packages to 10.4.x +- ############################################################################ +- dogtagpki Pagure Issue #6 - Remove Policy Framework Deprecations (edewata) +- dogtagpki Pagure Issue #850 - JSS certificate validation function does not + pass up exact errors from NSS (edewata) +- dogtagpki Pagure Issue #1114 - [MAN] Generting Symmetric key fails with + key-generate when --usages verify is passed (vakwetu) +- dogtagpki Pagure Issue #1247 - Better error message when try to renew a + certificate that expires outside renewal grace period (vakwetu) +- dogtagpki Pagure Issue #1309 - Recovering of a revoked cert erroneously + reflects "active" in the token db cert entry (cfu) +- dogtagpki Pagure Issue #1490 - add option to bypass dnsdomainname check in + pkispawn (vakwetu) +- dogtagpki Pagure Issue #1517 - user-cert-add --serial CLI request to secure + port with remote CA shows authentication failure (edewata) +- dogtagpki Pagure Issue #1527 - TPS Enrollment always goes to "ca1" (cfu) +- dogtagpki Pagure Issue #1536 - CA EE: Submit caUserCert request without uid + does not show proper error message (vakwetu) +- dogtagpki Pagure Issue #1663 - Add SCP03 support (jmagne) +- dogtagpki Pagure Issue #1664 - [BUG] Add ability to disallow TPS to enroll + a single user on multiple tokens. (jmagne) +- dogtagpki Pagure Issue #1710 - Add profile component that copies CN to SAN + (ftweedal) +- dogtagpki Pagure Issue #1741 - ECDSA Certificates Generated by Certificate + System fail NIST validation test with parameter field. (cfu) +- dogtagpki Pagure Issue #1897 - [MAN] Man page for logging configuration. + (edewata) +- dogtagpki Pagure Issue #1920 - [MAN] Man page for PKCS #12 utilities + (edewata) +- dogtagpki Pagure Issue #2275 - add options to enable/disable cert or crl + publishing. (vakwetu) +- dogtagpki Pagure Issue #2289 - [MAN] pki ca-cert-request-submit fails + presumably because of missing authentication even if it should not require + any (edewata) +- dogtagpki Pagure Issue #2450 - Unable to search certificate requests using + the latest request ID (edewata) +- dogtagpki Pagure Issue #2453 - IPA replica-prepare failed with error + "Profile caIPAserviceCert Not Found" (ftweedal) +- dogtagpki Pagure Issue #2457 - Misleading Logging for HSM (edewata) +- dogtagpki Pagure Issue #2460 - Typo in comment line of + UserPwdDirAuthentication.java (edewata) +- dogtagpki Pagure Issue #2463 - Troubleshooting improvements (edewata) +- dogtagpki Pagure Issue #2466 - two-step externally-signed CA installation + fails due to missing AuthorityID (ftweedal) +- dogtagpki Pagure Issue #2475 - Multiple host authority entries created + (ftweedal) +- dogtagpki Pagure Issue #2476 - Miscellaneous Minor Changes (edewata) +- dogtagpki Pagure Issue #2478 - pkispawn fails as it is not able to find + openssl as a dependency package (mharmsen) +- dogtagpki Pagure Issue #2483 - Unable to read an encrypted email using + renewed tokens (jmagne) +- dogtagpki Pagure Issue #2486 - Automatic recovery of encryption cert is not + working when a token is physically damaged and a temporary token is issue + (jmagne) +- dogtagpki Pagure Issue #2496 -Cert/Key recovery is successful when the cert + serial number and key id on the ldap user mismatches (cfu) +- dogtagpki Pagure Issue #2497 - KRA installation failed against + externally-signed CA with partial certificate chain (edewata) +- dogtagpki Pagure Issue #2498 -Token format with external reg fails when + op.format.externalRegAddToToken.revokeCert=true (cfu) +- dogtagpki Pagure Issue #2500 - Problems with FIPS mode (edewata) +- dogtagpki Pagure Issue #2505 - Fix packaging duplicates of classes in + multiple jar files (edewata) +- dogtagpki Pagure Issue #2510 - PIN_RESET policy is not giving expected + results when set on a token (jmagne) +- dogtagpki Pagure Issue #2513 -TPS token enrollment fails to + setupSecureChannel when TPS and TKS security db is on fips mode. (jmagne) +- dogtagpki Pagure Issue #2523 - Changes to target.agent.approve.list + parameter is not reflected in the TPS Web UI (edewata) +- dogtagpki Pagure Issue #2524 - Remove xenroll.dll from pki-core (mharmsen) +- dogtagpki Pagure Issue #2525 - [RFE] FreeIPA to Dogtag permission mapping + plugin (ftweedal) +- dogtagpki Pagure Issue #2532 - [RFE] add express archivals and retrievals + from KRA (vakwetu) +- dogtagpki Pagure Issue #2534 - Automatic recovery of encryption cert - CA + and TPS tokendb shows different certificate status (cfu) +- dogtagpki Pagure Issue #2543 - Unable to install subordinate CA with HSM in + FIPS mode (edewata) +- dogtagpki Pagure Issue #2544 - TPS throws "err=6" when attempting to format + and enroll G&D Cards (jmagne) +- dogtagpki Pagure Issue #2552 - pkispawn does not change default ecc key size + from nistp256 when nistp384 is specified in spawn config (jmagne) +- dogtagpki Pagure Issue #2556 - pkispawn fails to create PKI subsystem on + FIPS enabled system (edewata) +- dogtagpki Pagure Issue #2564 - pki-tomcat for 10+ minutes before generating + cert (edewata) +- dogtagpki Pagure Issue #2569 - Token memory not wiped after key deletion + (jmagne) +- dogtagpki Pagure Issue #2570 - Problem with default AJP hostname in IPv6 + environment. (edewata) +- dogtagpki Pagure Issue #2571 - Request ID undefined for CA signing + certificate (vakwetu) +- dogtagpki Pagure Issue #2573 - CA Certificate Issuance Date displayed on CA + website incorrect (vakwetu) +- dogtagpki Pagure Issue #2579 - NumberFormatException in + LDAPProfileSubsystem (ftweedal) +- dogtagpki Pagure Issue #2582 - Access banner (edewata) +- dogtagpki Pagure Issue #2601 - Return revocation reason in GET + /ca/rest/certs/{id} response. (ftweedal) +- ############################################################################ + +* Mon Mar 6 2017 Dogtag Team <pki-devel@redhat.com> 10.4.0-0.1 - Updated version number to 10.4.0-0.1 +- NOTE: Original date was Mon Aug 8 2016 + +* Mon Mar 6 2017 Dogtag Team <pki-devel@redhat.com> 10.3.5-13 +- PKI TRAC Ticket #1710 - Add profile component that copies CN to SAN (ftweedal) + +* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 10.3.5-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Jan 31 2017 Dogtag Team <pki-devel@redhat.com> 10.3.5-11 + +* Thu Dec 22 2016 Miro HronĨok <mhroncok@redhat.com> - 10.3.5-10 +- Rebuild for Python 3.6 (Fedora 26) + +* Tue Dec 13 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-9 +- PKI TRAC Ticket #1517 - user-cert-add --serial CLI request to secure port + with remote CA shows authentication failure (edewata) +- PKI TRAC Ticket #1897 - [MAN] Man page for logging configuration. (edewata) +- PKI TRAC Ticket #1920 - [MAN] Man page for PKCS #12 utilities (edewata) +- PKI TRAC Ticket #2226 - KRA installation: NullPointerException in + ProxyRealm.findSecurityConstraints (edewata) +- PKI TRAC Ticket #2289 - [MAN] pki ca-cert-request-submit fails presumably + because of missing authentication even if it should not require any (edewata) +- PKI TRAC Ticket #2523 - Changes to target.agent.approve.list parameter is + not reflected in the TPS Web UI [pki-base] (edewata) +- PKI TRAC Ticket #2534 - Automatic recovery of encryption cert - CA and TPS + tokendb shows different certificate status (cfu) +- PKI TRAC Ticket #2543 - Unable to install subordinate CA with HSM in FIPS + mode (edewata) +- PKI TRAC Ticket #2544 - TPS throws "err=6" when attempting to format and + enroll G&D Cards (jmagne) +- PKI TRAC Ticket #2552 - pkispawn does not change default ecc key size from + nistp256 when nistp384 is specified in spawn config (jmagne) + +* Fri Nov 4 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-8 +- PKI TRAC Ticket #850 - JSS certificate validation function does not pass up + exact errors from NSS (edewata) + (Failed to start pki-tomcatd Service - "ipa-cacert-manage renew" failed?) +- PKI TRAC Ticket #1247 - Better error message when try to renew a certificate + that expires outside renewal grace period (alee) +- PKI TRAC Ticket #1536 - CA EE: Submit caUserCert request without uid does + not show proper error message (alee) +- PKI TRAC Ticket #2460 - Typo in comment line of UserPwdDirAuthentication.java + (edewata) +- PKI TRAC Ticket #2486 - Automatic recovery of encryption cert is not working + when a token is physically damaged and a temporary token is issued (jmagne) +- PKI TRAC Ticket #2498 - Token format with external reg fails when + op.format.externalRegAddToToken.revokeCert=true (cfu) +- PKI TRAC Ticket #2500 - Problems with FIPS mode (edewata) +- PKI TRAC Ticket #2500 - Problems with FIPS mode (edewata) + (added KRA key recovery via CLI in FIPS mode) +- PKI TRAC Ticket #2510 - PIN_RESET policy is not giving expected results when + set on a token (jmagne) +- PKI TRAC Ticket #2513 - TPS token enrollment fails to setupSecureChannel + when TPS and TKS security db is on fips mode. (jmagne) +- Reverted patches associated with + PKI TRAC Ticket #2523 - Changes to target.agent.approve.list parameter is + not reflected in the TPS Web UI + +* Mon Oct 10 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-7 +- PKI TRAC Ticket #1527 - TPS Enrollment always goes to "ca1" (cfu) +- PKI TRAC Ticket #1664 - [BUG] Add ability to disallow TPS to enroll a single + user on multiple tokens. (jmagne) +- PKI TRAC Ticket #2463 - Troubleshooting improvements (edewata) +- PKI TRAC Ticket #2466 - two-step externally-signed CA installation fails due + to missing AuthorityID (ftweedal) +- PKI TRAC Ticket #2475 - Multiple host authority entries created (ftweedal) +- PKI TRAC Ticket #2476 - Dogtag 10.4.0 Miscellaneous Minor Changes + (edewata) +- PKI TRAC Ticket #2478 - pkispawn fails as it is not able to find openssl as a + dependency package (mharmsen) +- PKI TRAC Ticket #2483 - Unable to read an encrypted email using renewed + tokens (jmagne) +- PKI TRAC Ticket #2496 - Cert/Key recovery is successful when the cert serial + number and key id on the ldap user mismatches (cfu) +- PKI TRAC Ticket #2497 - KRA installation failed against externally-signed CA + with partial certificate chain (edewata) +- PKI TRAC Ticket #2505 - Fix packaging duplicates of classes in multiple jar + files (edewata) +- Fix for flake8 errors on Fedora 26 (cheimes) + +* Fri Sep 9 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-6 +- Revert Patch: PKI TRAC Ticket #2449 - Unable to create system certificates + in different tokens (edewata) + +* Tue Sep 6 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-5 +- PKI TRAC Ticket #1638 - Lightweight CAs: revoke certificate on CA deletion + (ftweedal) +- PKI TRAC Ticket #2436 - Dogtag 10.3.6: Miscellaneous Enhancements + (edewata) +- PKI TRAC Ticket #2443 - Prevent deletion of host CA's keys if LWCA entry + deleted (ftweedal) +- PKI TRAC Ticket #2444 - Authority entry without entryUSN is skipped even if + USN plugin enabled (ftweedal) +- PKI TRAC Ticket #2446 - pkispawn: make subject_dn defaults unique per + instance name (for shared HSM) (cfu) +- PKI TRAC Ticket #2447 - CertRequestInfo has incorrect URLs (vakwetu) +- PKI TRAC Ticket #2449 - Unable to create system certificates in different + tokens (edewata) + +* Mon Aug 29 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-4 +- PKI TRAC Ticket #1578 - Authentication Instance Id PinDirEnrollment with authType value as SslclientAuth is not working (jmagne) +- PKI TRAC TIcket #2414 - pki pkcs12-cert-del shows a successfully deleted message when a wrong nickname is provided (gkapoor) +- PKI TRAC Ticket #2423 - pki_ca_signing_token when not specified does not fallback to pki_token_name value (edewata) +- PKI TRAC Ticket #2436 - Dogtag 10.3.6: Miscellaneous Enhancements (akasurde) - ticket remains open +- PKI TRAC Ticket #2439 - Outdated deployment descriptors in upgraded server(edewata) + +* Mon Aug 22 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-3 +- spec file changes + +* Mon Aug 22 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-2 +- PKI TRAC Ticket #690 - [MAN] pki-tools man pages (mharmsen) + - CMCEnroll +- PKI TRAC Ticket #833 - pki user-mod fullName="" gives an error message + "PKIException: LDAP error (21): error result" (edewata) +- PKI TRAC Ticket #2431 - Errors noticed during ipa server upgrade. + (cheimes, edewata, mharmsen) +- PKI TRAC Ticket #2432 - Kra-selftest behavior is not as expected (edewata) +- PKI TRAC Ticket #2436 - Dogtag 10.3.6: Miscellaneous Enhancements + (edewata, mharmsen) +- PKI TRAC Ticket #2437 - TPS UI: while adding certs for users from TPSUI pem + format with/without header works while pkcs7 with header is not allowed + (edewata) +- PKI TRAC Ticket #2440 - Optional CA signing CSR for migration (edewata) * Mon Aug 8 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-1 - Updated version number to 10.3.5-1 -* Tue Jul 5 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-0.1 +* Tue Jul 19 2016 Dogtag Team <pki-devel@redhat.com> 10.3.5-0.1 - Updated version number to 10.3.5-0.1 +- NOTE: Original date was Tue Jul 5 2016 -* Tue Jun 21 2016 Dogtag Team <pki-devel@redhat.com> 10.3.4-0.1 +* Tue Jul 19 2016 Dogtag Team <pki-devel@redhat.com> 10.3.4-0.1 - Updated version number to 10.3.4-0.1 +- NOTE: Original date was Tue Jun 21 2016 + +* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 10.3.3-4 +- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages + +* Tue Jul 5 2016 Dogtag Team <pki-devel@redhat.com> 10.3.3-3 +- PKI TRAC Ticket #691 - [MAN] pki-server man pages (mharmsen) +- PKI TRAC Ticket #1114 - [MAN] Generting Symmetric key fails with + key-generate when --usages verify is passed (jmagne) +- PKI TRAC Ticket #1306 - [RFE] Add granularity to token termination in TPS + (cfu) +- PKI TRAC Ticket #1308 - [RFE] Provide ability to perform off-card key + generation for non-encryption token keys (cfu) +- PKI TRAC Ticket #1405 - [MAN] Add additional HSM details to + 'pki_default.cfg' & 'pkispawn' man pages (mharmsen) +- PKI TRAC Ticket #1607 - [MAN] man pkispawn has inadequate description for + shared vs non shared tomcat instance installation (mharmsen) +- PKI TRAC Ticket #1664 - [BUG] Add ability to disallow TPS to enroll a single + user on multiple tokens. (jmagne) +- PKI TRAC Ticket #1711 - CLI :: pki-server ca-cert-request-find throws + IOError (edewata, ftweedal) +- PKI TRAC Ticket #2285 - freeipa fails to start correctly after pki-core + update on upgraded system (ftweedal) +- PKI TRAC Ticket #2311 - When pki_token_name=Internal, consider normalizing + it to "internal" (mharmsen) +- PKI TRAC Ticket #2349 - Separated TPS does not automatically receive shared + secret from remote TKS (jmagne) +- PKI TRAC Ticket #2364 - CLI :: pki-server ca-cert-request-show throws + attribute error (ftweedal) +- PKI TRAC Ticket #2368 - pki-server subsystem subcommands throws error with + --help option (edewata) +- PKI TRAC Ticket #2374 - KRA cloning overwrites CA signing certificate trust + flags (edewata) +- PKI TRAC Ticket #2380 - Pki-server instance commands throws exception while + specifying invalid parameters. (edewata) +- PKI TRAC Ticket #2384 - CA installation with HSM prompts for HSM password + during silent installation (edewata) +- PKI TRAC Ticket #2385 - Upgraded CA lacks ca.sslserver.certreq in CS.cfg + (ftweedal) +- PKI TRAC Ticket #2387 - Add config for default OCSP URI if none given + (ftweedal) +- PKI TRAC Ticket #2388 - CA creation responds 500 if certificate issuance + fails (ftweedal) +- PKI TRAC Ticket #2389 - Installation: subsystem certs could have notAfter + beyond CA signing cert in case of external or existing CA (cfu) +- PKI TRAC Ticket #2390 - Dogtag 10.3.4: Miscellaneous Enhancements + (akasurde, edewata) + +* Thu Jun 30 2016 Dogtag Team <pki-devel@redhat.com> 10.3.3-2 +- PKI TRAC Ticket #2373 - Fedora 25: RestEasy 3.0.6 ==> 3.0.17 breaks + pki-core (ftweedal) * Mon Jun 20 2016 Dogtag Team <pki-devel@redhat.com> 10.3.3-1 - Updated release number to 10.3.3-1 @@ -92,7 +92,7 @@ python_files = tests/python/*.py [flake8] ignore = N802,N806,N812 exclude = .tox,*.egg,dist,build,conf.py,tests/dogtag/*,.git -filename = *.py,pki,pkidestroy,pki-upgrade,pki-server,pki-server-upgrade,pkispawn,[0-9][0-9]-* +filename = *.py,pkidestroy,pki-upgrade,pki-server,pki-server-upgrade,pkispawn,[0-9][0-9]-* show-source = true max-line-length = 99 # application-import-names = pki |
