From 1b59b9cb9a9c3cae2eb904305fa6f3899d3dc820 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Sat, 25 Jan 2014 23:07:49 -0500 Subject: Added SymKeyGen service --- .../kra/src/com/netscape/kra/SymKeyGenService.java | 280 +++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 base/kra/src/com/netscape/kra/SymKeyGenService.java (limited to 'base/kra/src') diff --git a/base/kra/src/com/netscape/kra/SymKeyGenService.java b/base/kra/src/com/netscape/kra/SymKeyGenService.java new file mode 100644 index 000000000..c3a03d968 --- /dev/null +++ b/base/kra/src/com/netscape/kra/SymKeyGenService.java @@ -0,0 +1,280 @@ +// --- 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) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.kra; + +import java.io.CharConversionException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +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; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.key.SymKeyGenerationRequest; +import com.netscape.certsrv.kra.IKeyRecoveryAuthority; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IService; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.security.IStorageKeyUnit; +import com.netscape.cmscore.dbs.KeyRecord; + +/** + * This implementation implements SecurityData archival operations. + *

+ * + * @version $Revision$, $Date$ + */ +public class SymKeyGenService implements IService { + + private final static String DEFAULT_OWNER = "IPA Agent"; + public final static String ATTR_KEY_RECORD = "keyRecord"; + private final static String STATUS_ACTIVE = "active"; + + private IKeyRecoveryAuthority mKRA = null; + private IStorageKeyUnit mStorageUnit = null; + private ILogger signedAuditLogger = CMS.getSignedAuditLogger(); + + private final static String LOGGING_SIGNED_AUDIT_SYMKEY_GEN_REQUEST_PROCESSED = + "LOGGING_SIGNED_AUDIT_SYMKEY_GEN_REQUEST_PROCESSED_6"; + + public SymKeyGenService(IKeyRecoveryAuthority kra) { + mKRA = kra; + mStorageUnit = kra.getStorageKeyUnit(); + } + + /** + * Performs the service of archiving Security Data. + * represented by this request. + *

+ * + * @param request + * The request that needs service. The service may use + * attributes stored in the request, and may update the + * values, or store new ones. + * @return + * an indication of whether this request is still pending. + * 'false' means the request will wait for further notification. + * @exception EBaseException indicates major processing failure. + */ + public boolean serviceRequest(IRequest request) + throws EBaseException { + String id = request.getRequestId().toString(); + String clientId = request.getExtDataInString(IRequest.SECURITY_DATA_CLIENT_ID); + String algorithm = request.getExtDataInString(IRequest.SYMKEY_GEN_ALGORITHM); + + String usageStr = request.getExtDataInString(IRequest.SYMKEY_GEN_USAGES); + List usages = new ArrayList(Arrays.asList(usageStr.split(","))); + + String keySizeStr = request.getExtDataInString(IRequest.SYMKEY_GEN_SIZE); + int keySize = Integer.parseInt(keySizeStr); + + CMS.debug("SymKeyGenService.serviceRequest. Request id: " + id); + CMS.debug("SymKeyGenService.serviceRequest algorithm: " + algorithm); + + String owner = getOwnerName(request); + String subjectID = auditSubjectID(); + + //Check here even though restful layer checks for this. + if (algorithm == null || clientId == null || keySize <= 0) { + auditSymKeyGenRequestProcessed(subjectID, ILogger.FAILURE, request.getRequestId(), + clientId, null, "Bad data in request"); + throw new EBaseException("Bad data in SymKeyGenService.serviceRequest"); + } + + CryptoToken token = mStorageUnit.getToken(); + KeyGenAlgorithm kgAlg = getKeyGenAlgorithm(algorithm); + + SymmetricKey.Usage keyUsages[]; + if (usages.size() > 0) { + keyUsages = new SymmetricKey.Usage[usages.size()]; + int index = 0; + for (String usage : usages) { + switch (usage) { + case SymKeyGenerationRequest.DECRYPT_USAGE: + keyUsages[index] = SymmetricKey.Usage.DECRYPT; + break; + case SymKeyGenerationRequest.ENCRYPT_USAGE: + keyUsages[index] = SymmetricKey.Usage.ENCRYPT; + break; + case SymKeyGenerationRequest.WRAP_USAGE: + keyUsages[index] = SymmetricKey.Usage.WRAP; + break; + case SymKeyGenerationRequest.UWRAP_USAGE: + keyUsages[index] = SymmetricKey.Usage.UNWRAP; + break; + case SymKeyGenerationRequest.SIGN_USAGE: + keyUsages[index] = SymmetricKey.Usage.SIGN; + break; + case SymKeyGenerationRequest.VERIFY_USAGE: + keyUsages[index] = SymmetricKey.Usage.VERIFY; + break; + default: + throw new EBaseException("Invalid usage"); + } + index++; + } + } else { + keyUsages = new SymmetricKey.Usage[2]; + keyUsages[0] = SymmetricKey.Usage.DECRYPT; + keyUsages[1] = SymmetricKey.Usage.ENCRYPT; + } + + SymmetricKey sk = null; + try { + KeyGenerator kg = token.getKeyGenerator(kgAlg); + kg.setKeyUsages(keyUsages); + kg.temporaryKeys(true); + sk = kg.generate(); + CMS.debug("SymKeyGenService:wrap() session key generated on slot: " + token.getName()); + } catch (TokenException | IllegalStateException | CharConversionException | NoSuchAlgorithmException e) { + auditSymKeyGenRequestProcessed(subjectID, ILogger.FAILURE, request.getRequestId(), + clientId, null, "Failed to generate symmetric key"); + throw new EBaseException("Errors in generating symmetric key: " + e); + } + + String keyType = null; + + byte[] publicKey = null; + byte privateSecurityData[] = null; + + if (sk != null) { + privateSecurityData = mStorageUnit.wrap(sk); + } else { // We have no data. + auditSymKeyGenRequestProcessed(subjectID, ILogger.FAILURE, request.getRequestId(), + clientId, null, "Failed to create security data to archive"); + throw new EBaseException("Failed to create security data to archive!"); + } + + // create key record + KeyRecord rec = new KeyRecord(null, publicKey, + privateSecurityData, owner, + algorithm, owner); + + rec.set(IKeyRecord.ATTR_CLIENT_ID, clientId); + + //Now we need a serial number for our new key. + if (rec.getSerialNumber() != null) { + auditSymKeyGenRequestProcessed(subjectID, ILogger.FAILURE, request.getRequestId(), + clientId, null, CMS.getUserMessage("CMS_KRA_INVALID_STATE")); + throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE")); + } + + IKeyRepository storage = mKRA.getKeyRepository(); + BigInteger serialNo = storage.getNextSerialNumber(); + + if (serialNo == null) { + mKRA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_KRA_GET_NEXT_SERIAL")); + auditSymKeyGenRequestProcessed(subjectID, ILogger.FAILURE, request.getRequestId(), + clientId, null, "Failed to get next Key ID"); + throw new EBaseException(CMS.getUserMessage("CMS_KRA_INVALID_STATE")); + } + + rec.set(KeyRecord.ATTR_ID, serialNo); + rec.set(KeyRecord.ATTR_DATA_TYPE, keyType); + rec.set(KeyRecord.ATTR_STATUS, STATUS_ACTIVE); + request.setExtData(ATTR_KEY_RECORD, serialNo); + + CMS.debug("KRA adding Security Data key record " + serialNo); + storage.addKeyRecord(rec); + + auditSymKeyGenRequestProcessed(subjectID, ILogger.SUCCESS, request.getRequestId(), + clientId, serialNo.toString(), "None"); + + return true; + } + + KeyGenAlgorithm getKeyGenAlgorithm(String algorithm) throws EBaseException { + switch (algorithm) { + case "DES": + return KeyGenAlgorithm.DES; + case "DESede": + return KeyGenAlgorithm.DESede; + case "DES3": + return KeyGenAlgorithm.DES3; + case "RC4": + return KeyGenAlgorithm.RC4; + case "AES": + return KeyGenAlgorithm.AES; + case "RC2": + return KeyGenAlgorithm.RC2; + default: + throw new EBaseException("Invalid algorithm"); + } + } + + //ToDo: return real owner with auth + private String getOwnerName(IRequest request) { + return DEFAULT_OWNER; + } + + private void audit(String msg) { + if (signedAuditLogger == null) + return; + + signedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, + ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, + msg); + } + + private String auditSubjectID() { + if (signedAuditLogger == null) { + return null; + } + + String subjectID = null; + + // Initialize subjectID + SessionContext auditContext = SessionContext.getExistingContext(); + + if (auditContext != null) { + subjectID = (String) auditContext.get(SessionContext.USER_ID); + subjectID = (subjectID != null) ? subjectID.trim() : ILogger.NONROLEUSER; + } else { + subjectID = ILogger.UNIDENTIFIED; + } + + return subjectID; + } + + private void auditSymKeyGenRequestProcessed(String subjectID, String status, RequestId requestID, String clientID, + String keyID, String reason) { + String auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_SYMKEY_GEN_REQUEST_PROCESSED, + subjectID, + status, + requestID.toString(), + clientID, + keyID != null ? keyID : "None", + reason); + audit(auditMessage); + } +} \ No newline at end of file -- cgit