]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_apple_csp/lib/opensshCoding.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / opensshCoding.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2006,2011-2012,2014 Apple Inc. All Rights Reserved.
b1ab9ed8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/*
26 * opensshCoding.cpp - Encoding and decoding of OpenSSH format public keys.
27 *
b1ab9ed8
A
28 */
29
30#include "opensshCoding.h"
31#include <CoreFoundation/CFData.h>
6b200bc3
A
32#include <openssl/bn_legacy.h>
33#include <openssl/crypto_legacy.h>
b1ab9ed8
A
34#include <security_cdsa_utils/cuEnc64.h>
35
36#define SSH2_RSA_HEADER "ssh-rsa"
37#define SSH2_DSA_HEADER "ssh-dss"
38
39#ifndef NDEBUG
40#include <stdio.h>
41#define dprintf(s...) printf(s)
42#else
43#define dprintf(...)
44#endif
45
46#pragma mark --- commmon code ---
47
48uint32_t readUint32(
49 const unsigned char *&cp, // IN/OUT
50 unsigned &len) // IN/OUT
51{
52 uint32_t r = 0;
53
54 for(unsigned dex=0; dex<sizeof(uint32_t); dex++) {
55 r <<= 8;
56 r |= *cp++;
57 }
58 len -= 4;
59 return r;
60}
61
62void appendUint32(
63 CFMutableDataRef cfOut,
64 uint32_t ui)
65{
66 UInt8 buf[sizeof(uint32_t)];
67
68 for(int dex=(sizeof(uint32_t) - 1); dex>=0; dex--) {
69 buf[dex] = ui & 0xff;
70 ui >>= 8;
71 }
72 CFDataAppendBytes(cfOut, buf, sizeof(uint32_t));
73}
74
75
76/* parse text as decimal, return BIGNUM */
77static BIGNUM *parseDecimalBn(
78 const unsigned char *cp,
79 unsigned len)
80{
81 for(unsigned dex=0; dex<len; dex++) {
82 char c = *cp;
83 if((c < '0') || (c > '9')) {
84 return NULL;
85 }
86 }
87 char *str = (char *)malloc(len + 1);
88 memmove(str, cp, len);
89 str[len] = '\0';
90 BIGNUM *bn = NULL;
91 BN_dec2bn(&bn, str);
92 free(str);
93 return bn;
94}
95
96/* write BIGNUM, OpenSSH v2 format (with a 4-byte byte count) */
97static CSSM_RETURN appendBigNum2(
98 CFMutableDataRef cfOut,
99 const BIGNUM *bn)
100{
101 if(bn == NULL) {
102 dprintf("appendBigNum2: NULL bn");
103 return CSSMERR_CSP_INTERNAL_ERROR;
104 }
105 if (BN_is_zero(bn)) {
106 appendUint32(cfOut, 0);
107 return 0;
108 }
109 if(bn->neg) {
110 dprintf("appendBigNum2: negative numbers not supported\n");
111 return CSSMERR_CSP_INTERNAL_ERROR;
112 }
113 int numBytes = BN_num_bytes(bn);
79b9da22
A
114 unsigned char *buf = (unsigned char*)malloc(numBytes);
115 if (buf == NULL) {
116 dprintf("appendBigNum: Cannot allocate a temp BN buffer\n");
117 return CSSMERR_CSSM_MEMORY_ERROR;
118 }
b1ab9ed8
A
119 int moved = BN_bn2bin(bn, buf);
120 if(moved != numBytes) {
121 dprintf("appendBigNum: BN_bn2bin() screwup\n");
79b9da22 122 free(buf);
b1ab9ed8
A
123 return CSSMERR_CSP_INTERNAL_ERROR;
124 }
125 bool appendZero = false;
126 if(buf[0] & 0x80) {
127 /* prepend leading zero to make it positive */
128 appendZero = true;
129 numBytes++; // to encode the correct 4-byte length
130 }
131 appendUint32(cfOut, (uint32_t)numBytes);
132 if(appendZero) {
133 UInt8 z = 0;
134 CFDataAppendBytes(cfOut, &z, 1);
135 numBytes--; // to append the correct number of bytes
136 }
137 CFDataAppendBytes(cfOut, buf, numBytes);
138 memset(buf, 0, numBytes);
79b9da22 139 free(buf);
b1ab9ed8
A
140 return CSSM_OK;
141}
142
143/* read BIGNUM, OpenSSH-2 mpint version */
144static BIGNUM *readBigNum2(
145 const unsigned char *&cp, // IN/OUT
146 unsigned &remLen) // IN/OUT
147{
148 if(remLen < 4) {
149 dprintf("readBigNum2: short record(1)\n");
150 return NULL;
151 }
152 uint32_t bytes = readUint32(cp, remLen);
153 if(remLen < bytes) {
154 dprintf("readBigNum2: short record(2)\n");
155 return NULL;
156 }
157 BIGNUM *bn = BN_bin2bn(cp, bytes, NULL);
158 if(bn == NULL) {
159 dprintf("readBigNum2: BN_bin2bn error\n");
160 return NULL;
161 }
162 cp += bytes;
163 remLen -= bytes;
164 return bn;
165}
166
167/* Write BIGNUM, OpenSSH-1 decimal (public key) version */
168static CSSM_RETURN appendBigNumDec(
169 CFMutableDataRef cfOut,
170 const BIGNUM *bn)
171{
172 char *buf = BN_bn2dec(bn);
173 if(buf == NULL) {
174 dprintf("appendBigNumDec: BN_bn2dec() error");
175 return CSSMERR_CSP_INTERNAL_ERROR;
176 }
177 CFDataAppendBytes(cfOut, (const UInt8 *)buf, strlen(buf));
178 Free(buf);
179 return CSSM_OK;
180}
181
182/* write string, OpenSSH v2 format (with a 4-byte byte count) */
183static void appendString(
184 CFMutableDataRef cfOut,
185 const char *str,
186 unsigned strLen)
187{
188 appendUint32(cfOut, (uint32_t)strLen);
189 CFDataAppendBytes(cfOut, (UInt8 *)str, strLen);
190}
191
192/* skip whitespace */
193static void skipWhite(
194 const unsigned char *&cp,
195 unsigned &bytesLeft)
196{
197 while(bytesLeft != 0) {
198 if(isspace((int)(*cp))) {
199 cp++;
200 bytesLeft--;
201 }
202 else {
203 return;
204 }
205 }
206}
207
208/* find next whitespace or EOF - if EOF, rtn pointer points to one past EOF */
209static const unsigned char *findNextWhite(
210 const unsigned char *cp,
211 unsigned &bytesLeft)
212{
213 while(bytesLeft != 0) {
214 if(isspace((int)(*cp))) {
215 return cp;
216 }
217 cp++;
218 bytesLeft--;
219 }
220 return cp;
221}
222
223
224/*
225 * Decode components from an SSHv2 public key.
226 * Also verifies the leading header, e.g. "ssh-rsa".
227 * The returned decodedBlob is algorithm-specific.
228 */
229static CSSM_RETURN parseSSH2PubKey(
230 const unsigned char *key,
231 unsigned keyLen,
232 const char *header, // SSH2_RSA_HEADER, SSH2_DSA_HEADER
233 unsigned char **decodedBlob, // mallocd and RETURNED
234 unsigned *decodedBlobLen) // RETURNED
235{
427c49bc 236 size_t len = strlen(header);
b1ab9ed8
A
237 *decodedBlob = NULL;
238
239 /* ID string plus at least one space */
240 if(keyLen < (len + 1)) {
241 dprintf("parseSSH2PubKey: short record(1)\n");
242 return CSSMERR_CSP_INVALID_KEY;
243 }
244
245 if(memcmp(header, key, len)) {
246 dprintf("parseSSH2PubKey: bad header (1)\n");
247 return CSSMERR_CSP_INVALID_KEY;
248 }
249 key += len;
250 if(*key++ != ' ') {
251 dprintf("parseSSH2PubKey: bad header (2)\n");
252 return CSSMERR_CSP_INVALID_KEY;
253 }
254 keyLen -= (len + 1);
255
256 /* key points to first whitespace after header */
257 skipWhite(key, keyLen);
258 if(keyLen == 0) {
259 dprintf("parseSSH2PubKey: short key\n");
260 return CSSMERR_CSP_INVALID_KEY;
261 }
262
263 /* key is start of base64 blob */
264 const unsigned char *encodedBlob = key;
265 const unsigned char *endBlob = findNextWhite(key, keyLen);
427c49bc 266 unsigned encodedBlobLen = (unsigned)(endBlob - encodedBlob);
b1ab9ed8
A
267
268 /* decode base 64 */
269 *decodedBlob = cuDec64(encodedBlob, encodedBlobLen, decodedBlobLen);
270 if(*decodedBlob == NULL) {
271 dprintf("parseSSH2PubKey: base64 decode error\n");
272 return CSSMERR_CSP_INVALID_KEY;
273 }
274
275 /* skip remainder; it's comment */
276
277 return CSSM_OK;
278}
279
280
281#pragma mark -- RSA OpenSSHv1 ---
282
283CSSM_RETURN RSAPublicKeyEncodeOpenSSH1(
284 RSA *rsa,
285 const CssmData &descData,
286 CssmOwnedData &encodedKey)
287{
288 CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
289 CSSM_RETURN ourRtn = CSSM_OK;
290
291 /*
292 * Format is
293 * num_bits in decimal
294 * <space>
295 * e, bignum in decimal
296 * <space>
297 * n, bignum in decimal
298 * <space>
299 * optional comment
300 * newline
301 */
302 unsigned numBits = BN_num_bits(rsa->n);
303 char bitString[20];
304 UInt8 c = ' ';
305
306 snprintf(bitString, sizeof(bitString), "%u ", numBits);
307 CFDataAppendBytes(cfOut, (const UInt8 *)bitString, strlen(bitString));
427c49bc 308 if((ourRtn = appendBigNumDec(cfOut, rsa->e))) {
b1ab9ed8
A
309 goto errOut;
310 }
311 CFDataAppendBytes(cfOut, &c, 1);
427c49bc 312 if((ourRtn = appendBigNumDec(cfOut, rsa->n))) {
b1ab9ed8
A
313 goto errOut;
314 }
315
316 if(descData.Length) {
317 /* optional comment */
318 CFDataAppendBytes(cfOut, &c, 1);
319 CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
320 }
321
322 c = '\n';
323 CFDataAppendBytes(cfOut, &c, 1);
324 encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
325errOut:
326 CFRelease(cfOut);
327 return ourRtn;
328}
329
330CSSM_RETURN RSAPublicKeyDecodeOpenSSH1(
331 RSA *rsa,
332 void *p,
333 size_t length)
334{
335 const unsigned char *cp = (const unsigned char *)p;
427c49bc 336 unsigned remLen = (unsigned)length;
b1ab9ed8
A
337
338 skipWhite(cp, remLen);
339
340 /*
341 * cp points to start of size_in_bits in ASCII decimal; we really don't care about
342 * this field. Find next space.
343 */
344 cp = findNextWhite(cp, remLen);
345 if(remLen == 0) {
346 dprintf("RSAPublicKeyDecodeOpenSSH1: short key (1)\n");
347 return CSSMERR_CSP_INVALID_KEY;
348 }
349 skipWhite(cp, remLen);
350 if(remLen == 0) {
351 dprintf("RSAPublicKeyDecodeOpenSSH1: short key (2)\n");
352 return CSSMERR_CSP_INVALID_KEY;
353 }
354
355 /*
356 * cp points to start of e
357 */
358 const unsigned char *ep = findNextWhite(cp, remLen);
359 if(remLen == 0) {
360 dprintf("RSAPublicKeyDecodeOpenSSH1: short key (3)\n");
361 return CSSMERR_CSP_INVALID_KEY;
362 }
427c49bc 363 unsigned len = (unsigned)(ep - cp);
b1ab9ed8
A
364 rsa->e = parseDecimalBn(cp, len);
365 if(rsa->e == NULL) {
366 return CSSMERR_CSP_INVALID_KEY;
367 }
368 cp += len;
369
370 skipWhite(cp, remLen);
371 if(remLen == 0) {
372 dprintf("RSAPublicKeyDecodeOpenSSH1: short key (4)\n");
373 return -1;
374 }
375
376 /* cp points to start of n */
377 ep = findNextWhite(cp, remLen);
427c49bc 378 len = (unsigned)(ep - cp);
b1ab9ed8
A
379 rsa->n = parseDecimalBn(cp, len);
380 if(rsa->n == NULL) {
381 return CSSMERR_CSP_INVALID_KEY;
382 }
383
384 /* remainder is comment, we ignore */
385 return CSSM_OK;
386
387}
388
389CSSM_RETURN RSAPrivateKeyEncodeOpenSSH1(
390 RSA *rsa,
391 const CssmData &descData,
392 CssmOwnedData &encodedKey)
393{
394 CFDataRef cfOut;
395 CSSM_RETURN ourRtn;
396
427c49bc 397 ourRtn = encodeOpenSSHv1PrivKey(rsa, descData.Data, (unsigned)descData.Length, NULL, &cfOut);
b1ab9ed8
A
398 if(ourRtn) {
399 return ourRtn;
400 }
401 encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
402 CFRelease(cfOut);
403 return CSSM_OK;
404}
405
406extern CSSM_RETURN RSAPrivateKeyDecodeOpenSSH1(
407 RSA *openKey,
408 void *p,
409 size_t length)
410{
427c49bc 411 return decodeOpenSSHv1PrivKey((const unsigned char *)p, (unsigned)length,
b1ab9ed8
A
412 openKey, NULL, NULL, NULL);
413}
414
415#pragma mark -- RSA OpenSSHv2 ---
416
417CSSM_RETURN RSAPublicKeyEncodeOpenSSH2(
418 RSA *rsa,
419 const CssmData &descData,
420 CssmOwnedData &encodedKey)
421{
422 unsigned char *b64 = NULL;
423 unsigned b64Len;
424 UInt8 c;
425
426 /*
427 * First, the inner base64-encoded blob, consisting of
428 * ssh-rsa
429 * e
430 * n
431 */
432 CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
433 CSSM_RETURN ourRtn = CSSM_OK;
434 appendString(cfOut, SSH2_RSA_HEADER, strlen(SSH2_RSA_HEADER));
427c49bc 435 if((ourRtn = appendBigNum2(cfOut, rsa->e))) {
b1ab9ed8
A
436 goto errOut;
437 }
427c49bc 438 if((ourRtn = appendBigNum2(cfOut, rsa->n))) {
b1ab9ed8
A
439 goto errOut;
440 }
441
442 /* base64 encode that */
427c49bc 443 b64 = cuEnc64((unsigned char *)CFDataGetBytePtr(cfOut), (unsigned)CFDataGetLength(cfOut), &b64Len);
b1ab9ed8
A
444
445 /* cuEnc64 added newline and NULL, which we really don't want */
446 b64Len -= 2;
447
448 /* Now start over, dropping that base64 into a public blob. */
449 CFDataSetLength(cfOut, 0);
450 CFDataAppendBytes(cfOut, (UInt8 *)SSH2_RSA_HEADER, strlen(SSH2_RSA_HEADER));
451 c = ' ';
452 CFDataAppendBytes(cfOut, &c, 1);
453 CFDataAppendBytes(cfOut, b64, b64Len);
454
455 if(descData.Length) {
456 /* optional comment */
457 CFDataAppendBytes(cfOut, &c, 1);
458 CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
459 }
460
461 /* finish it with a newline */
462 c = '\n';
463 CFDataAppendBytes(cfOut, &c, 1);
464
465 encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
466errOut:
467 CFRelease(cfOut);
468 if(b64) {
469 free(b64);
470 }
471 return ourRtn;
472}
473
474CSSM_RETURN RSAPublicKeyDecodeOpenSSH2(
475 RSA *rsa,
476 void *p,
477 size_t length)
478{
479 const unsigned char *key = (const unsigned char *)p;
427c49bc 480 unsigned keyLen = (unsigned)length;
b1ab9ed8
A
481 CSSM_RETURN ourRtn;
482
483 /*
484 * Verify header
485 * get base64-decoded blob
486 */
487 unsigned char *decodedBlob = NULL;
488 unsigned decodedBlobLen = 0;
427c49bc 489 if((ourRtn = parseSSH2PubKey(key, keyLen, SSH2_RSA_HEADER, &decodedBlob, &decodedBlobLen))) {
b1ab9ed8
A
490 return ourRtn;
491 }
492 /* subsequent errors to errOut: */
493
494 /*
495 * The inner base64-decoded blob, consisting of
496 * ssh-rsa
497 * e
498 * n
499 */
500 uint32_t decLen;
501 unsigned len;
502
503 key = decodedBlob;
504 keyLen = decodedBlobLen;
505 if(keyLen < 12) {
506 /* three length fields at least */
507 dprintf("RSAPublicKeyDecodeOpenSSH2: short record(2)\n");
508 ourRtn = -1;
509 goto errOut;
510 }
511 decLen = readUint32(key, keyLen);
512 len = strlen(SSH2_RSA_HEADER);
513 if(decLen != len) {
514 dprintf("RSAPublicKeyDecodeOpenSSH2: bad header (2)\n");
515 ourRtn = CSSMERR_CSP_INVALID_KEY;
516 goto errOut;
517 }
518 if(memcmp(SSH2_RSA_HEADER, key, len)) {
519 dprintf("RSAPublicKeyDecodeOpenSSH2: bad header (1)\n");
520 return CSSMERR_CSP_INVALID_KEY;
521 }
522 key += len;
523 keyLen -= len;
524
525 rsa->e = readBigNum2(key, keyLen);
526 if(rsa->e == NULL) {
527 ourRtn = CSSMERR_CSP_INVALID_KEY;
528 goto errOut;
529 }
530 rsa->n = readBigNum2(key, keyLen);
531 if(rsa->n == NULL) {
532 ourRtn = CSSMERR_CSP_INVALID_KEY;
533 goto errOut;
534 }
535
536errOut:
537 free(decodedBlob);
538 return ourRtn;
539}
540
541#pragma mark -- DSA OpenSSHv2 ---
542
543CSSM_RETURN DSAPublicKeyEncodeOpenSSH2(
544 DSA *dsa,
545 const CssmData &descData,
546 CssmOwnedData &encodedKey)
547{
548 unsigned char *b64 = NULL;
549 unsigned b64Len;
550 UInt8 c;
551
552 /*
553 * First, the inner base64-encoded blob, consisting of
554 * ssh-dss
555 * p
556 * q
557 * g
558 * pub_key
559 */
560 CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
561 int ourRtn = 0;
562 appendString(cfOut, SSH2_DSA_HEADER, strlen(SSH2_DSA_HEADER));
427c49bc 563 if((ourRtn = appendBigNum2(cfOut, dsa->p))) {
b1ab9ed8
A
564 goto errOut;
565 }
427c49bc 566 if((ourRtn = appendBigNum2(cfOut, dsa->q))) {
b1ab9ed8
A
567 goto errOut;
568 }
427c49bc 569 if((ourRtn = appendBigNum2(cfOut, dsa->g))) {
b1ab9ed8
A
570 goto errOut;
571 }
427c49bc 572 if((ourRtn = appendBigNum2(cfOut, dsa->pub_key))) {
b1ab9ed8
A
573 goto errOut;
574 }
575
576 /* base64 encode that */
427c49bc 577 b64 = cuEnc64((unsigned char *)CFDataGetBytePtr(cfOut), (unsigned)CFDataGetLength(cfOut), &b64Len);
b1ab9ed8
A
578
579 /* cuEnc64 added newline and NULL, which we really don't want */
580 b64Len -= 2;
581
582 /* Now start over, dropping that base64 into a public blob. */
583 CFDataSetLength(cfOut, 0);
584 CFDataAppendBytes(cfOut, (UInt8 *)SSH2_DSA_HEADER, strlen(SSH2_DSA_HEADER));
585 c = ' ';
586 CFDataAppendBytes(cfOut, &c, 1);
587 CFDataAppendBytes(cfOut, b64, b64Len);
588
589 if(descData.Length) {
590 /* optional comment */
591 CFDataAppendBytes(cfOut, &c, 1);
592 CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
593 }
594
595 /* finish it with a newline */
596 c = '\n';
597 CFDataAppendBytes(cfOut, &c, 1);
598
599 encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
600
601errOut:
602 CFRelease(cfOut);
603 if(b64) {
604 free(b64);
605 }
606 return ourRtn;
607}
608
609CSSM_RETURN DSAPublicKeyDecodeOpenSSH2(
610 DSA *dsa,
611 void *p,
612 size_t length)
613{
614 const unsigned char *key = (const unsigned char *)p;
427c49bc 615 unsigned keyLen = (unsigned)length;
b1ab9ed8
A
616 CSSM_RETURN ourRtn;
617
618 /*
619 * Verify header
620 * get base64-decoded blob
621 */
622 unsigned char *decodedBlob = NULL;
623 unsigned decodedBlobLen = 0;
427c49bc 624 if((ourRtn = parseSSH2PubKey(key, keyLen, SSH2_DSA_HEADER, &decodedBlob, &decodedBlobLen))) {
b1ab9ed8
A
625 return ourRtn;
626 }
627 /* subsequent errors to errOut: */
628
629 /*
630 * The inner base64-decoded blob, consisting of
631 * ssh-dss
632 * p
633 * q
634 * g
635 * pub_key
636 */
637 uint32_t decLen;
638 unsigned len;
639
640 key = decodedBlob;
641 keyLen = decodedBlobLen;
642 if(keyLen < 20) {
643 /* five length fields at least */
644 dprintf("DSAPublicKeyDecodeOpenSSH2: short record(2)\n");
645 ourRtn = CSSMERR_CSP_INVALID_KEY;
646 goto errOut;
647 }
648 decLen = readUint32(key, keyLen);
649 len = strlen(SSH2_DSA_HEADER);
650 if(decLen != len) {
651 dprintf("DSAPublicKeyDecodeOpenSSH2: bad header (2)\n");
652 ourRtn = CSSMERR_CSP_INVALID_KEY;
653 goto errOut;
654 }
655 if(memcmp(SSH2_DSA_HEADER, key, len)) {
656 dprintf("DSAPublicKeyDecodeOpenSSH2: bad header (1)\n");
657 return CSSMERR_CSP_INVALID_KEY;
658 }
659 key += len;
660 keyLen -= len;
661
662 dsa->p = readBigNum2(key, keyLen);
663 if(dsa->p == NULL) {
664 ourRtn = CSSMERR_CSP_INVALID_KEY;
665 goto errOut;
666 }
667 dsa->q = readBigNum2(key, keyLen);
668 if(dsa->q == NULL) {
669 ourRtn = CSSMERR_CSP_INVALID_KEY;
670 goto errOut;
671 }
672 dsa->g = readBigNum2(key, keyLen);
673 if(dsa->g == NULL) {
674 ourRtn = CSSMERR_CSP_INVALID_KEY;
675 goto errOut;
676 }
677 dsa->pub_key = readBigNum2(key, keyLen);
678 if(dsa->pub_key == NULL) {
679 ourRtn = CSSMERR_CSP_INVALID_KEY;
680 goto errOut;
681 }
682
683errOut:
684 free(decodedBlob);
685 return ourRtn;
686
687}
688