2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2020 Nordix Foundation.
4 * Copyright (C) 2021 Nokia.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.oom.certservice.cmpv2client.impl;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.security.SecureRandom;
27 import java.util.Date;
28 import java.util.Objects;
30 import org.bouncycastle.asn1.ASN1Encodable;
31 import org.bouncycastle.asn1.ASN1EncodableVector;
32 import org.bouncycastle.asn1.ASN1GeneralizedTime;
33 import org.bouncycastle.asn1.ASN1OctetString;
34 import org.bouncycastle.asn1.DEROctetString;
35 import org.bouncycastle.asn1.DEROutputStream;
36 import org.bouncycastle.asn1.DERSequence;
37 import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
38 import org.bouncycastle.asn1.cmp.InfoTypeAndValue;
39 import org.bouncycastle.asn1.cmp.PKIBody;
40 import org.bouncycastle.asn1.cmp.PKIHeader;
41 import org.bouncycastle.asn1.cmp.PKIHeaderBuilder;
42 import org.bouncycastle.asn1.x500.X500Name;
43 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
44 import org.bouncycastle.asn1.x509.GeneralName;
45 import org.onap.oom.certservice.cmpv2client.exceptions.CmpClientException;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 public final class CmpUtil {
51 private static final Logger LOGGER = LoggerFactory.getLogger(CmpUtil.class);
52 private static final SecureRandom SECURE_RANDOM = new SecureRandom();
53 public static final int RANDOM_BYTE_LENGTH = 16;
54 public static final int RANDOM_SEED = 1000;
60 * Validates specified object reference is not null.
62 * @param argument T - the type of the reference.
63 * @param message message - detail message to be used in the event that a NullPointerException is
65 * @return The Object if not null
67 public static <T> T notNull(T argument, String message) {
68 return Objects.requireNonNull(argument, message + " must not be null");
72 * Validates String object reference is not null and not empty.
74 * @param stringArg String Object that need to be validated.
77 public static boolean isNullOrEmpty(String stringArg) {
78 return (stringArg != null && !stringArg.trim().isEmpty());
82 * Creates a random number than can be used for sendernonce, transactionId and salts.
84 * @return bytes containing a random number string representing a nonce
86 static byte[] createRandomBytes() {
87 LOGGER.info("Generating random array of bytes");
88 byte[] randomBytes = new byte[RANDOM_BYTE_LENGTH];
89 SECURE_RANDOM.nextBytes(randomBytes);
94 * Creates a random integer than can be used to represent a transactionId or determine the number
95 * iterations in a protection algorithm.
97 * @return bytes containing a random number string representing a nonce
99 static int createRandomInt(int range) {
100 LOGGER.info("Generating random integer");
101 return SECURE_RANDOM.nextInt(range) + RANDOM_SEED;
105 * Generates protected bytes of a combined PKIHeader and PKIBody.
107 * @param header Header of PKIMessage containing common parameters
108 * @param body Body of PKIMessage containing specific information for message
109 * @return bytes representing the PKIHeader and PKIBody thats to be protected
111 static byte[] generateProtectedBytes(PKIHeader header, PKIBody body) throws CmpClientException {
112 LOGGER.info("Generating array of bytes representing PkiHeader and PkiBody");
114 ASN1EncodableVector vector = new ASN1EncodableVector();
117 ASN1Encodable protectedPart = new DERSequence(vector);
118 try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
119 DEROutputStream out = new DEROutputStream(baos);
120 out.writeObject(protectedPart);
121 res = baos.toByteArray();
122 } catch (IOException ioe) {
123 CmpClientException cmpClientException =
124 new CmpClientException("IOException occurred while creating protectedBytes", ioe);
125 LOGGER.error("IOException occurred while creating protectedBytes");
126 throw cmpClientException;
132 * Generates a PKIHeader object.
134 * @param subjectDn distinguished name of Subject
135 * @param issuerDn distinguished name of external CA
136 * @param protectionAlg protection Algorithm used to protect PKIMessage
137 * @param senderKid sender identifier for receiver used for verification
140 static PKIHeader generatePkiHeader(
141 X500Name subjectDn, X500Name issuerDn, AlgorithmIdentifier protectionAlg, String senderKid) {
142 LOGGER.info("Generating a Pki Header Builder");
143 PKIHeaderBuilder pkiHeaderBuilder =
144 new PKIHeaderBuilder(
145 PKIHeader.CMP_2000, new GeneralName(subjectDn), new GeneralName(issuerDn));
147 pkiHeaderBuilder.setMessageTime(new ASN1GeneralizedTime(new Date()));
148 pkiHeaderBuilder.setSenderNonce(new DEROctetString(createRandomBytes()));
149 pkiHeaderBuilder.setTransactionID(new DEROctetString(createRandomBytes()));
150 pkiHeaderBuilder.setProtectionAlg(protectionAlg);
151 pkiHeaderBuilder.setGeneralInfo(new InfoTypeAndValue(CMPObjectIdentifiers.it_implicitConfirm));
152 pkiHeaderBuilder.setSenderKID(mapToAsn1OctetString(senderKid));
154 return pkiHeaderBuilder.build();
157 private static ASN1OctetString mapToAsn1OctetString(String string) {
158 return string != null ? new DEROctetString(string.getBytes()) : null;