aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/pkix/src/main/java/org/spongycastle/pkcs/PKCS12PfxPdu.java
blob: 6a229e486e13b661655201b3b2e427e31d67c3a0 (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
package org.spongycastle.pkcs;

import java.io.IOException;

import org.spongycastle.asn1.ASN1OctetString;
import org.spongycastle.asn1.ASN1Primitive;
import org.spongycastle.asn1.ASN1Sequence;
import org.spongycastle.asn1.pkcs.ContentInfo;
import org.spongycastle.asn1.pkcs.MacData;
import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
import org.spongycastle.asn1.pkcs.Pfx;
import org.spongycastle.asn1.x509.AlgorithmIdentifier;
import org.spongycastle.cert.CertIOException;
import org.spongycastle.util.Arrays;

/**
 * A holding class for the PKCS12 Pfx structure.
 */
public class PKCS12PfxPdu
{
    private Pfx pfx;

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

    public PKCS12PfxPdu(Pfx pfx)
    {
        this.pfx = pfx;
    }

    public PKCS12PfxPdu(byte[] pfx)
        throws IOException
    {
        this(parseBytes(pfx));
    }

    /**
     * Return the content infos in the AuthenticatedSafe contained in this Pfx.
     *
     * @return an array of ContentInfo.
     */
    public ContentInfo[] getContentInfos()
    {
        ASN1Sequence seq = ASN1Sequence.getInstance(ASN1OctetString.getInstance(this.pfx.getAuthSafe().getContent()).getOctets());
        ContentInfo[] content = new ContentInfo[seq.size()];

        for (int i = 0; i != seq.size(); i++)
        {
            content[i] = ContentInfo.getInstance(seq.getObjectAt(i));
        }

        return content;
    }

    /**
     * Return whether or not there is MAC attached to this file.
     *
     * @return true if there is, false otherwise.
     */
    public boolean hasMac()
    {
        return pfx.getMacData() != null;
    }

    /**
     * Return the algorithm identifier describing the MAC algorithm
     *
     * @return the AlgorithmIdentifier representing the MAC algorithm, null if none present.
     */
    public AlgorithmIdentifier getMacAlgorithmID()
    {
        MacData md = pfx.getMacData();

        if (md != null)
        {
            return md.getMac().getAlgorithmId();
        }

        return null;
    }

    /**
     * Verify the MacData attached to the PFX is consistent with what is expected.
     *
     * @param macCalcProviderBuilder provider builder for the calculator for the MAC
     * @param password password to use
     * @return true if mac data is valid, false otherwise.
     * @throws PKCSException if there is a problem evaluating the MAC.
     * @throws IllegalStateException if no MAC is actually present
     */
    public boolean isMacValid(PKCS12MacCalculatorBuilderProvider macCalcProviderBuilder, char[] password)
        throws PKCSException
    {
        if (hasMac())
        {
            MacData pfxmData = pfx.getMacData();
            MacDataGenerator mdGen = new MacDataGenerator(macCalcProviderBuilder.get(new AlgorithmIdentifier(pfxmData.getMac().getAlgorithmId().getAlgorithm(), new PKCS12PBEParams(pfxmData.getSalt(), pfxmData.getIterationCount().intValue()))));

            try
            {
                MacData mData = mdGen.build(
                    password,
                    ASN1OctetString.getInstance(pfx.getAuthSafe().getContent()).getOctets());

                return Arrays.constantTimeAreEqual(mData.getEncoded(), pfx.getMacData().getEncoded());
            }
            catch (IOException e)
            {
                throw new PKCSException("unable to process AuthSafe: " + e.getMessage());
            }
        }

        throw new IllegalStateException("no MAC present on PFX");
    }

    /**
     * Return the underlying ASN.1 object.
     *
     * @return a Pfx object.
     */
    public Pfx toASN1Structure()
    {
        return pfx;
    }

    public byte[] getEncoded()
        throws IOException
    {
        return toASN1Structure().getEncoded();
    }

    /**
     * Return a Pfx with the outer wrapper encoded as asked for. For example, Pfx is a usually
     * a BER encoded object, to get one with DefiniteLength encoding use:
     * <pre>
     * getEncoded(ASN1Encoding.DL)
     * </pre>
     * @param encoding encoding style (ASN1Encoding.DER, ASN1Encoding.DL, ASN1Encoding.BER)
     * @return a byte array containing the encoded object.
     * @throws IOException
     */
    public byte[] getEncoded(String encoding)
        throws IOException
    {
        return toASN1Structure().getEncoded(encoding);
    }
}