]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/pkcs8.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / pkcs8.cpp
1 /*
2 * Copyright (c) 2000-2001,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // pkcs8.cpp - PKCS8 key wrap/unwrap support.
21 //
22
23
24 #include "pkcs8.h"
25 #include "AppleCSPUtils.h"
26 #include "AppleCSPKeys.h"
27 #include <Security/keyTemplates.h>
28 #include <security_asn1/SecNssCoder.h>
29 #include <security_asn1/nssUtils.h>
30 #include "AppleCSPSession.h"
31 #include <Security/cssmapple.h>
32
33 /*
34 * Given a key in PKCS8 format, fill in the following
35 * header fields:
36 *
37 * CSSM_KEYBLOB_FORMAT Format
38 * CSSM_ALGORITHMS AlgorithmId
39 * uint32 LogicalKeySizeInBits
40 */
41 void AppleCSPSession::pkcs8InferKeyHeader(
42 CssmKey &key)
43 {
44 /*
45 * Incoming key blob is a PrivateKeyInfo. Take it apart
46 * to get its algorithm info, from which we infer other
47 * fields.
48 */
49 NSS_PrivateKeyInfo privKeyInfo;
50 SecNssCoder coder;
51 CSSM_DATA &keyData = key.KeyData;
52
53 memset(&privKeyInfo, 0, sizeof(privKeyInfo));
54 if(coder.decodeItem(keyData, kSecAsn1PrivateKeyInfoTemplate,
55 &privKeyInfo)) {
56 errorLog0("pkcs8InferKeyHeader decode error\n");
57 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
58 }
59
60 CSSM_KEYHEADER &hdr = key.KeyHeader;
61 if(!cssmOidToAlg(&privKeyInfo.algorithm.algorithm,
62 &hdr.AlgorithmId)) {
63 errorLog0("pkcs8InferKeyHeader unknown algorithm\n");
64 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
65 }
66
67 switch(hdr.AlgorithmId) {
68 case CSSM_ALGID_RSA:
69 case CSSM_ALGID_ECDSA:
70 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
71 break;
72 case CSSM_ALGID_DSA:
73 /*
74 * Try openssl style first, though our default when
75 * wrapping is FIPS186
76 */
77 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
78 break;
79 default:
80 /* punt */
81 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
82 break;
83 }
84
85 /*
86 * Find someone who knows about this key and ask them the
87 * key size. infoProvider() throws if no provider found.
88 */
89 CSSM_KEY_SIZE keySize;
90 try {
91 unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
92 provider->QueryKeySizeInBits(keySize);
93 }
94 catch(const CssmError &cerror) {
95 /*
96 * Special case: DSA private keys keys can be in two forms - FIPS186
97 * (for legacy implementations) and PKCS8 (for openssl). We're wired to
98 * *generate* FIPS186 blobs by default in pkcs8RawKeyFormat(), but to
99 * decode openssl-generated DSA private keys in wrapped FIPS186 format
100 * we have to try both.
101 */
102 if((cerror.error == CSSMERR_CSP_INVALID_KEY) &&
103 (hdr.AlgorithmId == CSSM_ALGID_DSA)) {
104 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
105 try {
106 unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
107 provider->QueryKeySizeInBits(keySize);
108 }
109 catch(...) {
110 /* out of luck */
111 throw;
112 }
113 }
114 else {
115 /* other error, give up */
116 throw;
117 }
118 }
119 catch(...) {
120 /* other (non-CSSM) error, give up */
121 throw;
122 }
123 hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
124 }
125
126 /*
127 * When doing a PKCS8 wrap operation on a reference key, this
128 * is used to infer the blob type to obtain before the encryption.
129 * App can override this with a
130 * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT
131 * context attribute.
132 */
133 CSSM_KEYBLOB_FORMAT pkcs8RawKeyFormat(
134 CSSM_ALGORITHMS keyAlg)
135 {
136 switch(keyAlg) {
137 case CSSM_ALGID_RSA:
138 case CSSM_ALGID_ECDSA:
139 return CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
140 case CSSM_ALGID_DSA:
141 return CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
142 default:
143 /* punt */
144 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
145 }
146 }
147
148 /*
149 * When doing a OPENSSL style wrap operation on a reference key, this
150 * is used to infer the blob type to obtain before the encryption.
151 * App can override this with a
152 * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT
153 * context attribute.
154 */
155 CSSM_KEYBLOB_FORMAT opensslRawKeyFormat(
156 CSSM_ALGORITHMS keyAlg)
157 {
158 switch(keyAlg) {
159 case CSSM_ALGID_RSA:
160 return CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
161 case CSSM_ALGID_DSA:
162 return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
163 case CSSM_ALGID_ECDSA:
164 return CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
165 default:
166 /* punt */
167 return CSSM_KEYBLOB_RAW_FORMAT_NONE;
168 }
169 }
170
171 /*
172 * Given a key in some kind of openssl format (just subsequent to decryption
173 * during an unwrap), fill in the following header fields:
174 *
175 * CSSM_KEYBLOB_FORMAT Format
176 * uint32 LogicalKeySizeInBits
177 */
178 void AppleCSPSession::opensslInferKeyHeader(
179 CssmKey &key)
180 {
181 CSSM_KEYHEADER &hdr = key.KeyHeader;
182 switch(hdr.AlgorithmId) {
183 case CSSM_ALGID_RSA:
184 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
185 break;
186 case CSSM_ALGID_DSA:
187 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
188 break;
189 case CSSM_ALGID_ECDSA:
190 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
191 break;
192 default:
193 /* punt */
194 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
195 return;
196 }
197
198 /* now figure out the key size by finding a provider for this key */
199 CSSM_KEY_SIZE keySize;
200 try {
201 unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
202 provider->QueryKeySizeInBits(keySize);
203 }
204 catch(...) {
205 /* no recovery possible */
206 throw;
207 }
208 hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
209 return;
210 }
211