Welcome to mirror list, hosted at ThFree Co, Russian Federation.

CertificateRequestMessage.java « crmf « cert « bouncycastle « org « jdk1.1 « main « src « pkix - gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ae328d6833a1aeb803f2ee4be2b55dc7a25200ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
package org.bouncycastle.cert.crmf;

import java.io.IOException;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.crmf.AttributeTypeAndValue;
import org.bouncycastle.asn1.crmf.CRMFObjectIdentifiers;
import org.bouncycastle.asn1.crmf.CertReqMsg;
import org.bouncycastle.asn1.crmf.CertTemplate;
import org.bouncycastle.asn1.crmf.Controls;
import org.bouncycastle.asn1.crmf.PKIArchiveOptions;
import org.bouncycastle.asn1.crmf.PKMACValue;
import org.bouncycastle.asn1.crmf.POPOSigningKey;
import org.bouncycastle.asn1.crmf.ProofOfPossession;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.OperatorCreationException;

/**
 * Carrier for a CRMF CertReqMsg.
 */
public class CertificateRequestMessage
{
    public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED;
    public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY;
    public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
    public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT;

    private CertReqMsg certReqMsg;
    private Controls controls;

    private static CertReqMsg parseBytes(byte[] encoding)
        throws IOException
    {
        try
        {
            return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding));
        }
        catch (ClassCastException e)
        {
            throw new CertIOException("malformed data: " + e.getMessage(), e);
        }
        catch (IllegalArgumentException e)
        {
            throw new CertIOException("malformed data: " + e.getMessage(), e);
        }
    }

    /**
     * Create a CertificateRequestMessage from the passed in bytes.
     *
     * @param certReqMsg BER/DER encoding of the CertReqMsg structure.
     * @throws IOException in the event of corrupted data, or an incorrect structure.
     */
    public CertificateRequestMessage(byte[] certReqMsg)
        throws IOException
    {
        this(parseBytes(certReqMsg));
    }

    public CertificateRequestMessage(CertReqMsg certReqMsg)
    {
        this.certReqMsg = certReqMsg;
        this.controls = certReqMsg.getCertReq().getControls();
    }

    /**
     * Return the underlying ASN.1 object defining this CertificateRequestMessage object.
     *
     * @return a CertReqMsg.
     */
    public CertReqMsg toASN1Structure()
    {
        return certReqMsg;
    }

    /**
     * Return the certificate template contained in this message.
     *
     * @return  a CertTemplate structure.
     */
    public CertTemplate getCertTemplate()
    {
        return this.certReqMsg.getCertReq().getCertTemplate();
    }

    /**
     * Return whether or not this request has control values associated with it.
     *
     * @return true if there are control values present, false otherwise.
     */
    public boolean hasControls()
    {
        return controls != null;
    }

    /**
     * Return whether or not this request has a specific type of control value.
     *
     * @param type the type OID for the control value we are checking for.
     * @return true if a control value of type is present, false otherwise.
     */
    public boolean hasControl(ASN1ObjectIdentifier type)
    {
        return findControl(type) != null;
    }

    /**
     * Return a control value of the specified type.
     *
     * @param type the type OID for the control value we are checking for.
     * @return the control value if present, null otherwise.
     */
    public Control getControl(ASN1ObjectIdentifier type)
    {
        AttributeTypeAndValue found = findControl(type);

        if (found != null)
        {
            if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
            {
                return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue()));
            }
            if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken))
            {
                return new RegTokenControl(DERUTF8String.getInstance(found.getValue()));
            }
            if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator))
            {
                return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue()));
            }
        }

        return null;
    }

    private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type)
    {
        if (controls == null)
        {
            return null;
        }

        AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray();
        AttributeTypeAndValue found = null;

        for (int i = 0; i != tAndVs.length; i++)
        {
            if (tAndVs[i].getType().equals(type))
            {
                found = tAndVs[i];
                break;
            }
        }

        return found;
    }

    /**
     * Return whether or not this request message has a proof-of-possession field in it.
     *
     * @return true if proof-of-possession is present, false otherwise.
     */
    public boolean hasProofOfPossession()
    {
        return this.certReqMsg.getPopo() != null;
    }

    /**
     * Return the type of the proof-of-possession this request message provides.
     *
     * @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement
     */
    public int getProofOfPossessionType()
    {
        return this.certReqMsg.getPopo().getType();
    }

    /**
     * Return whether or not the proof-of-possession (POP) is of the type popSigningKey and
     * it has a public key MAC associated with it.
     *
     * @return true if POP is popSigningKey and a PKMAC is present, false otherwise.
     */
    public boolean hasSigningKeyProofOfPossessionWithPKMAC()
    {
        ProofOfPossession pop = certReqMsg.getPopo();

        if (pop.getType() == popSigningKey)
        {
            POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());

            return popoSign.getPoposkInput().getPublicKeyMAC() != null;
        }

        return false;
    }

    /**
     * Return whether or not a signing key proof-of-possession (POP) is valid.
     *
     * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
     * @return true if the POP is valid, false otherwise.
     * @throws CRMFException if there is a problem in verification or content verifier creation.
     * @throws IllegalStateException if POP not appropriate.
     */
    public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider)
        throws CRMFException, IllegalStateException
    {
        ProofOfPossession pop = certReqMsg.getPopo();

        if (pop.getType() == popSigningKey)
        {
            POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());

            if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null)
            {
                throw new IllegalStateException("verification requires password check");
            }

            return verifySignature(verifierProvider, popoSign);
        }
        else
        {
            throw new IllegalStateException("not Signing Key type of proof of possession");
        }
    }

    /**
     * Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
     *
     * @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
     * @param macBuilder a suitable PKMACBuilder to create the MAC verifier.
     * @param password the password used to key the MAC calculation.
     * @return true if the POP is valid, false otherwise.
     * @throws CRMFException if there is a problem in verification or content verifier creation.
     * @throws IllegalStateException if POP not appropriate.
     */
    public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password)
        throws CRMFException, IllegalStateException
    {
        ProofOfPossession pop = certReqMsg.getPopo();

        if (pop.getType() == popSigningKey)
        {
            POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());

            if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null)
            {
                throw new IllegalStateException("no PKMAC present in proof of possession");
            }

            PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC();
            PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder);

            if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey()))
            {
                return verifySignature(verifierProvider, popoSign);
            }

            return false;
        }
        else
        {
            throw new IllegalStateException("not Signing Key type of proof of possession");
        }
    }

    private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign)
        throws CRMFException
    {
        ContentVerifier verifier;

        try
        {
            verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier());
        }
        catch (OperatorCreationException e)
        {
            throw new CRMFException("unable to create verifier: " + e.getMessage(), e);
        }

        if (popoSign.getPoposkInput() != null)
        {
            CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream());
        }
        else
        {
            CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream());
        }

        return verifier.verify(popoSign.getSignature().getBytes());
    }

    /**
     * Return the ASN.1 encoding of the certReqMsg we wrap.
     *
     * @return a byte array containing the binary encoding of the certReqMsg.
     * @throws IOException if there is an exception creating the encoding.
     */
    public byte[] getEncoded()
        throws IOException
    {
        return certReqMsg.getEncoded();
    }
}