0d0d7f34fb1918973032a2b5a0a3cc26e13f9d57
[oom/platform/cert-service.git] / certService / src / main / java / org / onap / oom / certservice / cmpv2client / impl / CmpUtil.java
1 /*-
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.oom.certservice.cmpv2client.impl;
23
24 import org.bouncycastle.asn1.ASN1Encodable;
25 import org.bouncycastle.asn1.ASN1EncodableVector;
26 import org.bouncycastle.asn1.ASN1GeneralizedTime;
27 import org.bouncycastle.asn1.ASN1OctetString;
28 import org.bouncycastle.asn1.DEROctetString;
29 import org.bouncycastle.asn1.DEROutputStream;
30 import org.bouncycastle.asn1.DERSequence;
31 import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
32 import org.bouncycastle.asn1.cmp.InfoTypeAndValue;
33 import org.bouncycastle.asn1.cmp.PKIBody;
34 import org.bouncycastle.asn1.cmp.PKIHeader;
35 import org.bouncycastle.asn1.cmp.PKIHeaderBuilder;
36 import org.bouncycastle.asn1.x500.X500Name;
37 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
38 import org.bouncycastle.asn1.x509.GeneralName;
39 import org.onap.oom.certservice.cmpv2client.exceptions.CmpClientException;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import java.io.ByteArrayOutputStream;
44 import java.io.IOException;
45 import java.security.SecureRandom;
46 import java.util.Date;
47 import java.util.Objects;
48
49 public final class CmpUtil {
50
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;
55
56     private CmpUtil() {
57     }
58
59     /**
60      * Validates specified object reference is not null.
61      *
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
64      *                 thrown.
65      * @return The Object if not null
66      */
67     public static <T> T notNull(T argument, String message) {
68         return Objects.requireNonNull(argument, message + " must not be null");
69     }
70
71     /**
72      * Validates String object reference is not null and not empty.
73      *
74      * @param stringArg String Object that need to be validated.
75      * @return boolean
76      */
77     public static boolean isNullOrEmpty(String stringArg) {
78         return (stringArg != null && !stringArg.trim().isEmpty());
79     }
80
81     /**
82      * Creates a random number than can be used for sendernonce, transactionId and salts.
83      *
84      * @return bytes containing a random number string representing a nonce
85      */
86     public static byte[] createRandomBytes() {
87         LOGGER.debug("Generating random array of bytes");
88         byte[] randomBytes = new byte[RANDOM_BYTE_LENGTH];
89         SECURE_RANDOM.nextBytes(randomBytes);
90         return randomBytes;
91     }
92
93     /**
94      * Creates a random integer than can be used to represent a transactionId or determine the number
95      * iterations in a protection algorithm.
96      *
97      * @return bytes containing a random number string representing a nonce
98      */
99     public static int createRandomInt(int range) {
100         LOGGER.debug("Generating random integer");
101         return SECURE_RANDOM.nextInt(range) + RANDOM_SEED;
102     }
103
104     /**
105      * Generates protected bytes of a combined PKIHeader and PKIBody.
106      *
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
110      */
111     public static byte[] generateProtectedBytes(PKIHeader header, PKIBody body) throws CmpClientException {
112         LOGGER.debug("Generating array of bytes representing PkiHeader and PkiBody");
113         byte[] res;
114         ASN1EncodableVector vector = new ASN1EncodableVector();
115         vector.add(header);
116         vector.add(body);
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;
127         }
128         return res;
129     }
130
131     /**
132      * Generates a PKIHeader object.
133      *
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
138      * @return PKIHeader
139      */
140     static PKIHeader generatePkiHeader(
141             X500Name subjectDn, X500Name issuerDn, AlgorithmIdentifier protectionAlg, String senderKid) {
142         LOGGER.debug("Generating a Pki Header Builder");
143         PKIHeaderBuilder pkiHeaderBuilder =
144                 new PKIHeaderBuilder(
145                         PKIHeader.CMP_2000, new GeneralName(subjectDn), new GeneralName(issuerDn));
146
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));
153
154         return pkiHeaderBuilder.build();
155     }
156
157     private static ASN1OctetString mapToAsn1OctetString(String string) {
158         return string != null ? new DEROctetString(string.getBytes()) : null;
159     }
160 }