]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_apple_csp/lib/opensshCoding.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / libsecurity_apple_csp / lib / opensshCoding.cpp
diff --git a/libsecurity_apple_csp/lib/opensshCoding.cpp b/libsecurity_apple_csp/lib/opensshCoding.cpp
deleted file mode 100644 (file)
index f331813..0000000
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
- * 
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-
-/*
- * opensshCoding.cpp - Encoding and decoding of OpenSSH format public keys.
- *
- * Created 8/29/2006 by dmitch.
- */
-
-#include "opensshCoding.h"
-#include <CoreFoundation/CFData.h>
-#include <openssl/bn.h>
-#include <openssl/crypto.h>
-#include <security_cdsa_utils/cuEnc64.h>
-
-#define SSH2_RSA_HEADER                "ssh-rsa"
-#define SSH2_DSA_HEADER                "ssh-dss"
-
-#ifndef        NDEBUG
-#include <stdio.h>
-#define dprintf(s...)          printf(s)
-#else
-#define dprintf(...)
-#endif
-
-#pragma mark --- commmon code --- 
-
-uint32_t readUint32(
-       const unsigned char *&cp,               // IN/OUT
-       unsigned &len)                                  // IN/OUT 
-{
-       uint32_t r = 0;
-       
-       for(unsigned dex=0; dex<sizeof(uint32_t); dex++) {
-               r <<= 8;
-               r |= *cp++;
-       }
-       len -= 4;
-       return r;
-}
-
-void appendUint32(
-       CFMutableDataRef cfOut,
-       uint32_t ui)
-{
-       UInt8 buf[sizeof(uint32_t)];
-       
-       for(int dex=(sizeof(uint32_t) - 1); dex>=0; dex--) {
-               buf[dex] = ui & 0xff;
-               ui >>= 8;
-       }
-       CFDataAppendBytes(cfOut, buf, sizeof(uint32_t));
-}
-
-
-/* parse text as decimal, return BIGNUM */
-static BIGNUM *parseDecimalBn(
-       const unsigned char *cp,
-       unsigned len)
-{
-       for(unsigned dex=0; dex<len; dex++) {
-               char c = *cp;
-               if((c < '0') || (c > '9')) {
-                       return NULL;
-               }
-       }
-       char *str = (char *)malloc(len + 1);
-       memmove(str, cp, len);
-       str[len] = '\0';
-       BIGNUM *bn = NULL;
-       BN_dec2bn(&bn, str);
-       free(str);
-       return bn;
-}
-       
-/* write BIGNUM, OpenSSH v2 format (with a 4-byte byte count) */
-static CSSM_RETURN appendBigNum2(
-       CFMutableDataRef cfOut,
-       const BIGNUM *bn)
-{
-       if(bn == NULL) {
-               dprintf("appendBigNum2: NULL bn");
-               return CSSMERR_CSP_INTERNAL_ERROR;
-       }
-       if (BN_is_zero(bn)) {
-               appendUint32(cfOut, 0);
-               return 0;
-       }
-       if(bn->neg) {
-               dprintf("appendBigNum2: negative numbers not supported\n");
-               return CSSMERR_CSP_INTERNAL_ERROR;
-       }
-       int numBytes = BN_num_bytes(bn);
-       unsigned char buf[numBytes];
-       int moved = BN_bn2bin(bn, buf);
-       if(moved != numBytes) {
-               dprintf("appendBigNum: BN_bn2bin() screwup\n");
-               return CSSMERR_CSP_INTERNAL_ERROR;
-       }
-       bool appendZero = false;
-       if(buf[0] & 0x80) {
-               /* prepend leading zero to make it positive */
-               appendZero = true;
-               numBytes++;             // to encode the correct 4-byte length 
-       }
-       appendUint32(cfOut, (uint32_t)numBytes);
-       if(appendZero) {
-               UInt8 z = 0;
-               CFDataAppendBytes(cfOut, &z, 1);
-               numBytes--;             // to append the correct number of bytes
-       }
-       CFDataAppendBytes(cfOut, buf, numBytes);
-       memset(buf, 0, numBytes);
-       return CSSM_OK;
-}
-
-/* read BIGNUM, OpenSSH-2 mpint version */
-static BIGNUM *readBigNum2(
-       const unsigned char *&cp,       // IN/OUT
-       unsigned &remLen)                       // IN/OUT
-{
-       if(remLen < 4) {
-               dprintf("readBigNum2: short record(1)\n");
-               return NULL;
-       }
-       uint32_t bytes = readUint32(cp, remLen);
-       if(remLen < bytes) {
-               dprintf("readBigNum2: short record(2)\n");
-               return NULL;
-       }
-       BIGNUM *bn = BN_bin2bn(cp, bytes, NULL);
-       if(bn == NULL) {
-               dprintf("readBigNum2: BN_bin2bn error\n");
-               return NULL;
-       }
-       cp += bytes;
-       remLen -= bytes;
-       return bn;
-}
-
-/* Write BIGNUM, OpenSSH-1 decimal (public key) version */
-static CSSM_RETURN appendBigNumDec(
-       CFMutableDataRef cfOut, 
-       const BIGNUM *bn)
-{
-       char *buf = BN_bn2dec(bn);
-       if(buf == NULL) {
-               dprintf("appendBigNumDec: BN_bn2dec() error");
-               return CSSMERR_CSP_INTERNAL_ERROR;
-       }
-       CFDataAppendBytes(cfOut, (const UInt8 *)buf, strlen(buf));
-       Free(buf);
-       return CSSM_OK;
-}
-
-/* write string, OpenSSH v2 format (with a 4-byte byte count) */
-static void appendString(
-       CFMutableDataRef cfOut,
-       const char *str,
-       unsigned strLen)
-{
-       appendUint32(cfOut, (uint32_t)strLen);
-       CFDataAppendBytes(cfOut, (UInt8 *)str, strLen);
-}
-
-/* skip whitespace */
-static void skipWhite(
-       const unsigned char *&cp,
-       unsigned &bytesLeft)
-{
-       while(bytesLeft != 0) {
-               if(isspace((int)(*cp))) {
-                       cp++;
-                       bytesLeft--;
-               }
-               else {
-                       return;
-               }
-       }
-}
-
-/* find next whitespace or EOF - if EOF, rtn pointer points to one past EOF */
-static const unsigned char *findNextWhite(
-       const unsigned char *cp,
-       unsigned &bytesLeft)
-{
-       while(bytesLeft != 0) {
-               if(isspace((int)(*cp))) {
-                       return cp;
-               }
-               cp++;
-               bytesLeft--;
-       }
-       return cp;
-}
-
-
-/* 
- * Decode components from an SSHv2 public key.
- * Also verifies the leading header, e.g. "ssh-rsa".
- * The returned decodedBlob is algorithm-specific.
- */
-static CSSM_RETURN parseSSH2PubKey(
-       const unsigned char *key,
-       unsigned keyLen,
-       const char *header,                             // SSH2_RSA_HEADER, SSH2_DSA_HEADER
-       unsigned char **decodedBlob,    // mallocd and RETURNED
-       unsigned *decodedBlobLen)               // RETURNED
-{
-       size_t len = strlen(header);
-       *decodedBlob = NULL;
-       
-       /* ID string plus at least one space */
-       if(keyLen < (len + 1)) {
-               dprintf("parseSSH2PubKey: short record(1)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       
-       if(memcmp(header, key, len)) {
-               dprintf("parseSSH2PubKey: bad header (1)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       key += len;
-       if(*key++ != ' ') {
-               dprintf("parseSSH2PubKey: bad header (2)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       keyLen -= (len + 1);
-
-       /* key points to first whitespace after header */
-       skipWhite(key, keyLen);
-       if(keyLen == 0) {
-               dprintf("parseSSH2PubKey: short key\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       
-       /* key is start of base64 blob */
-       const unsigned char *encodedBlob = key;
-       const unsigned char *endBlob = findNextWhite(key, keyLen);
-       unsigned encodedBlobLen = (unsigned)(endBlob - encodedBlob);
-       
-       /* decode base 64 */
-       *decodedBlob = cuDec64(encodedBlob, encodedBlobLen, decodedBlobLen);
-       if(*decodedBlob == NULL) {
-               dprintf("parseSSH2PubKey: base64 decode error\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       
-       /* skip remainder; it's comment */
-       
-       return CSSM_OK;
-}
-       
-
-#pragma mark -- RSA OpenSSHv1 ---
-
-CSSM_RETURN RSAPublicKeyEncodeOpenSSH1(
-       RSA                     *rsa, 
-       const CssmData  &descData,
-       CssmOwnedData   &encodedKey)
-{
-       CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
-       CSSM_RETURN ourRtn = CSSM_OK;
-       
-       /*
-        * Format is
-        * num_bits in decimal
-        * <space>
-        * e, bignum in decimal
-        * <space>
-        * n, bignum in decimal
-        * <space>
-        * optional comment
-        * newline
-        */
-       unsigned numBits = BN_num_bits(rsa->n);
-       char bitString[20];
-       UInt8 c = ' ';
-
-       snprintf(bitString, sizeof(bitString), "%u ", numBits);
-       CFDataAppendBytes(cfOut, (const UInt8 *)bitString, strlen(bitString));
-       if((ourRtn = appendBigNumDec(cfOut, rsa->e))) {
-               goto errOut;
-       }
-       CFDataAppendBytes(cfOut, &c, 1);
-       if((ourRtn = appendBigNumDec(cfOut, rsa->n))) {
-               goto errOut;
-       }
-       
-       if(descData.Length) {
-               /* optional comment */
-               CFDataAppendBytes(cfOut, &c, 1);
-               CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
-       }
-
-       c = '\n';
-       CFDataAppendBytes(cfOut, &c, 1);
-       encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
-errOut:
-       CFRelease(cfOut);
-       return ourRtn;
-}
-
-CSSM_RETURN RSAPublicKeyDecodeOpenSSH1(
-       RSA                     *rsa, 
-       void                    *p, 
-       size_t                  length)
-{
-       const unsigned char *cp = (const unsigned char *)p;
-       unsigned remLen = (unsigned)length;
-       
-       skipWhite(cp, remLen);
-       
-       /* 
-        * cp points to start of size_in_bits in ASCII decimal; we really don't care about 
-        * this field. Find next space.
-        */
-       cp = findNextWhite(cp, remLen);
-       if(remLen == 0) {
-               dprintf("RSAPublicKeyDecodeOpenSSH1: short key (1)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       skipWhite(cp, remLen);
-       if(remLen == 0) {
-               dprintf("RSAPublicKeyDecodeOpenSSH1: short key (2)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       
-       /*
-        * cp points to start of e
-        */
-       const unsigned char *ep = findNextWhite(cp, remLen);
-       if(remLen == 0) {
-               dprintf("RSAPublicKeyDecodeOpenSSH1: short key (3)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       unsigned len = (unsigned)(ep - cp);
-       rsa->e = parseDecimalBn(cp, len);
-       if(rsa->e == NULL) {
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       cp += len;
-       
-       skipWhite(cp, remLen);
-       if(remLen == 0) {
-               dprintf("RSAPublicKeyDecodeOpenSSH1: short key (4)\n");
-               return -1;
-       }
-       
-       /* cp points to start of n */
-       ep = findNextWhite(cp, remLen);
-       len = (unsigned)(ep - cp);
-       rsa->n = parseDecimalBn(cp, len);
-       if(rsa->n == NULL) {
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       
-       /* remainder is comment, we ignore */
-       return CSSM_OK;
-
-}
-
-CSSM_RETURN RSAPrivateKeyEncodeOpenSSH1(
-       RSA                     *rsa, 
-       const CssmData  &descData,
-       CssmOwnedData   &encodedKey)
-{
-       CFDataRef cfOut;
-       CSSM_RETURN ourRtn;
-
-       ourRtn = encodeOpenSSHv1PrivKey(rsa, descData.Data, (unsigned)descData.Length, NULL, &cfOut);
-       if(ourRtn) {
-               return ourRtn;
-       }
-       encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
-       CFRelease(cfOut);
-       return CSSM_OK;
-}
-
-extern CSSM_RETURN RSAPrivateKeyDecodeOpenSSH1(
-       RSA                     *openKey, 
-       void                    *p, 
-       size_t                  length)
-{
-       return decodeOpenSSHv1PrivKey((const unsigned char *)p, (unsigned)length,
-               openKey, NULL, NULL, NULL);
-}
-
-#pragma mark -- RSA OpenSSHv2 ---
-
-CSSM_RETURN RSAPublicKeyEncodeOpenSSH2(
-       RSA                     *rsa, 
-       const CssmData  &descData,
-       CssmOwnedData   &encodedKey)
-{
-       unsigned char *b64 = NULL;
-       unsigned b64Len;
-       UInt8 c;
-       
-       /* 
-        * First, the inner base64-encoded blob, consisting of
-        * ssh-rsa
-        * e
-        * n
-        */
-       CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
-       CSSM_RETURN ourRtn = CSSM_OK;
-       appendString(cfOut, SSH2_RSA_HEADER, strlen(SSH2_RSA_HEADER));
-       if((ourRtn = appendBigNum2(cfOut, rsa->e))) {
-               goto errOut;
-       }
-       if((ourRtn = appendBigNum2(cfOut, rsa->n))) {
-               goto errOut;
-       }
-       
-       /* base64 encode that */
-       b64 = cuEnc64((unsigned char *)CFDataGetBytePtr(cfOut), (unsigned)CFDataGetLength(cfOut), &b64Len);
-       
-       /* cuEnc64 added newline and NULL, which we really don't want */
-       b64Len -= 2;
-       
-       /* Now start over, dropping that base64 into a public blob. */
-       CFDataSetLength(cfOut, 0);
-       CFDataAppendBytes(cfOut, (UInt8 *)SSH2_RSA_HEADER, strlen(SSH2_RSA_HEADER));
-       c = ' ';
-       CFDataAppendBytes(cfOut, &c, 1);
-       CFDataAppendBytes(cfOut, b64, b64Len);
-       
-       if(descData.Length) {
-               /* optional comment */
-               CFDataAppendBytes(cfOut, &c, 1);
-               CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
-       }
-       
-       /* finish it with a newline */
-       c = '\n';
-       CFDataAppendBytes(cfOut, &c, 1);
-       
-       encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
-errOut:
-       CFRelease(cfOut);
-       if(b64) {
-               free(b64);
-       }
-       return ourRtn;
-}
-
-CSSM_RETURN RSAPublicKeyDecodeOpenSSH2(
-       RSA                     *rsa, 
-       void                    *p, 
-       size_t                  length)
-{
-       const unsigned char *key = (const unsigned char *)p;
-       unsigned keyLen = (unsigned)length;
-       CSSM_RETURN ourRtn;
-       
-       /* 
-        * Verify header
-        * get base64-decoded blob 
-        */
-       unsigned char *decodedBlob = NULL;
-       unsigned decodedBlobLen = 0;
-       if((ourRtn = parseSSH2PubKey(key, keyLen, SSH2_RSA_HEADER, &decodedBlob, &decodedBlobLen))) {
-               return ourRtn;
-       }
-       /* subsequent errors to errOut: */
-       
-       /*
-        * The inner base64-decoded blob, consisting of
-        * ssh-rsa
-        * e
-        * n
-        */
-       uint32_t decLen;
-       unsigned len;
-       
-       key = decodedBlob;
-       keyLen = decodedBlobLen;
-       if(keyLen < 12) {
-               /* three length fields at least */
-               dprintf("RSAPublicKeyDecodeOpenSSH2: short record(2)\n");
-               ourRtn = -1;
-               goto errOut;
-       }
-       decLen = readUint32(key, keyLen);
-       len = strlen(SSH2_RSA_HEADER);
-       if(decLen != len) {
-               dprintf("RSAPublicKeyDecodeOpenSSH2: bad header (2)\n");
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       if(memcmp(SSH2_RSA_HEADER, key, len)) {
-               dprintf("RSAPublicKeyDecodeOpenSSH2: bad header (1)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       key += len;
-       keyLen -= len;
-       
-       rsa->e = readBigNum2(key, keyLen);
-       if(rsa->e == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       rsa->n = readBigNum2(key, keyLen);
-       if(rsa->n == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-
-errOut:
-       free(decodedBlob);
-       return ourRtn;
-}
-
-#pragma mark -- DSA OpenSSHv2 ---
-
-CSSM_RETURN DSAPublicKeyEncodeOpenSSH2(
-       DSA                     *dsa, 
-       const CssmData  &descData,
-       CssmOwnedData   &encodedKey)
-{
-       unsigned char *b64 = NULL;
-       unsigned b64Len;
-       UInt8 c;
-       
-       /* 
-        * First, the inner base64-encoded blob, consisting of
-        * ssh-dss
-        * p
-        * q
-        * g
-        * pub_key
-        */
-       CFMutableDataRef cfOut = CFDataCreateMutable(NULL, 0);
-       int ourRtn = 0;
-       appendString(cfOut, SSH2_DSA_HEADER, strlen(SSH2_DSA_HEADER));
-       if((ourRtn = appendBigNum2(cfOut, dsa->p))) {
-               goto errOut;
-       }
-       if((ourRtn = appendBigNum2(cfOut, dsa->q))) {
-               goto errOut;
-       }
-       if((ourRtn = appendBigNum2(cfOut, dsa->g))) {
-               goto errOut;
-       }
-       if((ourRtn = appendBigNum2(cfOut, dsa->pub_key))) {
-               goto errOut;
-       }
-       
-       /* base64 encode that */
-       b64 = cuEnc64((unsigned char *)CFDataGetBytePtr(cfOut), (unsigned)CFDataGetLength(cfOut), &b64Len);
-       
-       /* cuEnc64 added newline and NULL, which we really don't want */
-       b64Len -= 2;
-       
-       /* Now start over, dropping that base64 into a public blob. */
-       CFDataSetLength(cfOut, 0);
-       CFDataAppendBytes(cfOut, (UInt8 *)SSH2_DSA_HEADER, strlen(SSH2_DSA_HEADER));
-       c = ' ';
-       CFDataAppendBytes(cfOut, &c, 1);
-       CFDataAppendBytes(cfOut, b64, b64Len);
-       
-       if(descData.Length) {
-               /* optional comment */
-               CFDataAppendBytes(cfOut, &c, 1);
-               CFDataAppendBytes(cfOut, (UInt8 *)descData.Data, descData.Length);
-       }
-       
-       /* finish it with a newline */
-       c = '\n';
-       CFDataAppendBytes(cfOut, &c, 1);
-       
-       encodedKey.copy(CFDataGetBytePtr(cfOut), CFDataGetLength(cfOut));
-       
-errOut:
-       CFRelease(cfOut);
-       if(b64) {
-               free(b64);
-       }
-       return ourRtn;
-}
-
-CSSM_RETURN DSAPublicKeyDecodeOpenSSH2(
-       DSA                     *dsa, 
-       void                    *p, 
-       size_t                  length)
-{
-       const unsigned char *key = (const unsigned char *)p;
-       unsigned keyLen = (unsigned)length;
-       CSSM_RETURN ourRtn;
-       
-       /* 
-        * Verify header
-        * get base64-decoded blob 
-        */
-       unsigned char *decodedBlob = NULL;
-       unsigned decodedBlobLen = 0;
-       if((ourRtn = parseSSH2PubKey(key, keyLen, SSH2_DSA_HEADER, &decodedBlob, &decodedBlobLen))) {
-               return ourRtn;
-       }
-       /* subsequent errors to errOut: */
-       
-       /*
-        * The inner base64-decoded blob, consisting of
-        * ssh-dss
-        * p
-        * q
-        * g
-        * pub_key
-        */
-       uint32_t decLen;
-       unsigned len;
-       
-       key = decodedBlob;
-       keyLen = decodedBlobLen;
-       if(keyLen < 20) {
-               /* five length fields at least */
-               dprintf("DSAPublicKeyDecodeOpenSSH2: short record(2)\n");
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       decLen = readUint32(key, keyLen);
-       len = strlen(SSH2_DSA_HEADER);
-       if(decLen != len) {
-               dprintf("DSAPublicKeyDecodeOpenSSH2: bad header (2)\n");
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       if(memcmp(SSH2_DSA_HEADER, key, len)) {
-               dprintf("DSAPublicKeyDecodeOpenSSH2: bad header (1)\n");
-               return CSSMERR_CSP_INVALID_KEY;
-       }
-       key += len;
-       keyLen -= len;
-       
-       dsa->p = readBigNum2(key, keyLen);
-       if(dsa->p == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       dsa->q = readBigNum2(key, keyLen);
-       if(dsa->q == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       dsa->g = readBigNum2(key, keyLen);
-       if(dsa->g == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-       dsa->pub_key = readBigNum2(key, keyLen);
-       if(dsa->pub_key == NULL) {
-               ourRtn = CSSMERR_CSP_INVALID_KEY;
-               goto errOut;
-       }
-
-errOut:
-       free(decodedBlob);
-       return ourRtn;
-
-}
-