]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/Security/SecImportExportOpenSSH.cpp
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / Security / SecImportExportOpenSSH.cpp
diff --git a/OSX/libsecurity_keychain/Security/SecImportExportOpenSSH.cpp b/OSX/libsecurity_keychain/Security/SecImportExportOpenSSH.cpp
deleted file mode 100644 (file)
index d066c49..0000000
+++ /dev/null
@@ -1,633 +0,0 @@
-/*
- * Copyright (c) 2006,2011-2014 Apple 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.
- *
- */
-
-#include "SecImportExportOpenSSH.h"
-#include "SecImportExportUtils.h"
-#include "SecImportExportCrypto.h"
-#include <ctype.h>
-#include <CommonCrypto/CommonDigest.h> /* for CC_MD5_DIGEST_LENGTH */
-#include <security_utilities/debugging.h>
-#include <security_cdsa_utils/cuCdsaUtils.h>
-
-#define SecSSHDbg(args...)     secdebug("openssh", ## args)
-
-#define SSHv2_PUB_KEY_NAME             "OpenSSHv2 Public Key"
-#define SSHv1_PUB_KEY_NAME             "OpenSSHv1 Public Key"
-#define SSHv1_PRIV_KEY_NAME            "OpenSSHv1 Private Key"
-
-#pragma mark --- Utility functions ---
-
-/* 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;
-}
-
-/* obtain comment as the n'th whitespace-delimited field */
-static char *commentAsNthField(
-       const unsigned char *key,
-       unsigned keyLen,
-       unsigned n)
-
-{
-       unsigned dex;
-       
-       skipWhite(key, keyLen);
-       if(keyLen == 0) {
-               return NULL;
-       }
-       for(dex=0; dex<(n-1); dex++) {
-               key = findNextWhite(key, keyLen);
-               if(keyLen == 0) {
-                       return NULL;
-               }
-               skipWhite(key, keyLen);
-               if(keyLen == 0) {
-                       return NULL;
-               }
-       }
-       
-       /* cp points to start of nth field */
-       char *rtnStr = (char *)malloc(keyLen + 1);
-       memmove(rtnStr, key, keyLen);
-       if(rtnStr[keyLen - 1] == '\n') {
-               /* normal terminator - snip it off */
-               rtnStr[keyLen - 1] = '\0';
-       }
-       else {
-               rtnStr[keyLen] = '\0';
-       }
-       return rtnStr;
-
-}
-
-static 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;
-}
-
-static uint16_t readUint16(
-       const unsigned char *&cp,               // IN/OUT
-       unsigned &len)                                  // IN/OUT 
-{
-       uint16_t r = *cp++;
-       r <<= 8;
-       r |= *cp++;
-       len -= 2;
-       return r;
-}
-
-/* Skip over an SSHv1 private key formatted bignum */
-static void skipBigNum(
-       const unsigned char *&cp,               // IN/OUT
-       unsigned &len)                                  // IN/OUT 
-{
-       if(len < 2) {
-               cp += len;
-               len = 0;
-               return;
-       }
-       uint16 numBits = readUint16(cp, len);
-       unsigned numBytes = (numBits + 7) / 8;
-       if(numBytes > len) {
-               cp += len;
-               len = 0;
-               return;
-       }
-       cp += numBytes;
-       len -= numBytes;
-}
-
-static char *genPrintName(
-       const char *header,             // e.g. SSHv2_PUB_KEY_NAME
-       const char *comment)    // optional, from key 
-{
-       size_t totalLen = strlen(header) + 1;
-       if(comment) {
-               /* append ": <comment>" */
-               totalLen += strlen(comment);
-               totalLen += 2;
-       }
-       char *rtnStr = (char *)malloc(totalLen);
-       if(comment) {
-               snprintf(rtnStr, totalLen, "%s: %s", header, comment);
-       }
-       else {
-               strcpy(rtnStr, header);
-       }
-       return rtnStr;
-}
-
-#pragma mark --- Infer PrintName attribute from raw keys ---
-
-/* obtain comment from OpenSSHv2 public key */
-static char *opensshV2PubComment(
-       const unsigned char *key,
-       unsigned keyLen)
-{
-       /*
-        * The format here is
-        * header
-        * <space>
-        * keyblob
-        * <space>
-        * optional comment
-        * \n
-        */
-       char *comment = commentAsNthField(key, keyLen, 3);
-       char *rtnStr = genPrintName(SSHv2_PUB_KEY_NAME, comment);
-       if(comment) {
-               free(comment);
-       }
-       return rtnStr;
-}
-
-/* obtain comment from OpenSSHv1 public key */
-static char *opensshV1PubComment(
-       const unsigned char *key,
-       unsigned keyLen)
-{
-       /*
-        * Format:
-        * numbits
-        * <space>
-        * e (bignum in decimal)
-        * <space>
-        * n (bignum in decimal) 
-        * <space>
-        * optional comment 
-        * \n
-        */
-       char *comment = commentAsNthField(key, keyLen, 4);
-       char *rtnStr = genPrintName(SSHv1_PUB_KEY_NAME, comment);
-       if(comment) {
-               free(comment);
-       }
-       return rtnStr;
-}
-
-static const char *authfile_id_string = "SSH PRIVATE KEY FILE FORMAT 1.1\n";
-
-/* obtain comment from OpenSSHv1 private key, wrapped or clear */
-static char *opensshV1PrivComment(
-       const unsigned char *key,
-       unsigned keyLen)
-{
-       /* 
-        * Format:
-        * "SSH PRIVATE KEY FILE FORMAT 1.1\n"
-        * 1 byte cipherSpec
-        * 4 byte spares
-        * 4 bytes numBits
-        * bignum n
-        * bignum e
-        * 4 byte comment length 
-        * comment
-        * private key components, possibly encrypted 
-        *
-        * A bignum is encoded like so:
-        * 2 bytes numBits
-        * (numBits + 7)/8 bytes of data
-        */
-       /* length: ID string, NULL, Cipher, 4-byte spare */
-       size_t len = strlen(authfile_id_string);
-       if(keyLen < (len + 6)) {
-               return NULL;
-       }
-       if(memcmp(authfile_id_string, key, len)) {
-               return NULL;
-       }
-       key    += (len + 6);
-       keyLen -= (len + 6);
-       
-       /* key points to numBits */
-       if(keyLen < 4) {
-               return NULL;
-       }
-       key += 4;
-       keyLen -= 4;
-       
-       /* key points to n */
-       skipBigNum(key, keyLen);
-       if(keyLen == 0) {
-               return NULL;
-       }
-       skipBigNum(key, keyLen);
-       if(keyLen == 0) {
-               return NULL;
-       }
-       
-       char *comment = NULL;
-       uint32 commentLen = readUint32(key, keyLen);
-       if((commentLen != 0) && (commentLen <= keyLen)) {
-               comment = (char *)malloc(commentLen + 1);
-               memmove(comment, key, commentLen);
-               comment[commentLen] = '\0';
-       }
-       
-       char *rtnStr = genPrintName(SSHv1_PRIV_KEY_NAME, comment);
-       if(comment) {
-               free(comment);
-       }
-       return rtnStr;
-}
-
-/* 
- * Infer PrintName attribute from raw key's 'comment' field. 
- * Returned string is mallocd and must be freed by caller. 
- */
-char *impExpOpensshInferPrintName(
-       CFDataRef external, 
-       SecExternalItemType externType, 
-       SecExternalFormat externFormat)
-{
-       const unsigned char *key = (const unsigned char *)CFDataGetBytePtr(external);
-       unsigned keyLen = (unsigned)CFDataGetLength(external);
-       switch(externType) {
-               case kSecItemTypePublicKey:
-                       switch(externFormat) {
-                               case kSecFormatSSH:
-                                       return opensshV1PubComment(key, keyLen);
-                               case kSecFormatSSHv2:
-                                       return opensshV2PubComment(key, keyLen);
-                               default:
-                                       /* impossible, right? */
-                                       break;
-                       }
-                       break;
-               case kSecItemTypePrivateKey:
-                       switch(externFormat) {
-                               case kSecFormatSSH:
-                               case kSecFormatWrappedSSH:
-                                       return opensshV1PrivComment(key, keyLen);
-                               default:
-                                       break;
-                       }
-                       break;
-               default:
-                       break;
-       }
-       return NULL;
-}
-
-#pragma mark --- Infer DescriptiveData from PrintName ---
-
-/* 
- * Infer DescriptiveData (i.e., comment) from a SecKeyRef's PrintName
- * attribute.
- */
-void impExpOpensshInferDescData(
-       SecKeyRef keyRef,
-       CssmOwnedData &descData)
-{
-       OSStatus ortn;
-       SecKeychainAttributeInfo attrInfo;
-       SecKeychainAttrType     attrType = kSecKeyPrintName;
-       attrInfo.count = 1;
-       attrInfo.tag = &attrType;
-       attrInfo.format = NULL; 
-       SecKeychainAttributeList *attrList = NULL;
-       
-       ortn = SecKeychainItemCopyAttributesAndData(
-               (SecKeychainItemRef)keyRef, 
-               &attrInfo,
-               NULL,                   // itemClass
-               &attrList, 
-               NULL,                   // don't need the data
-               NULL);
-       if(ortn) {
-               SecSSHDbg("SecKeychainItemCopyAttributesAndData returned %ld", (unsigned long)ortn);
-               return;
-       }
-       /* subsequent errors to errOut: */
-       SecKeychainAttribute *attr = attrList->attr;
-               
-       /*
-        * On a previous import, we would have set this to something like 
-        * "OpenSSHv2 Public Key: comment".
-        * We want to strip off everything up to the actual comment.
-        */
-       unsigned toStrip = 0;   
-       
-       /* min length of attribute value for this code to be meaningful */
-       unsigned len = strlen(SSHv2_PUB_KEY_NAME) + 1;  
-       char *printNameStr = NULL;
-       if(len < attr->length) {
-               printNameStr = (char *)malloc(attr->length + 1);
-               memmove(printNameStr, attr->data, attr->length);
-               printNameStr[attr->length] = '\0';
-               if(strstr(printNameStr, SSHv2_PUB_KEY_NAME) == printNameStr) {
-                       toStrip = strlen(SSHv2_PUB_KEY_NAME);
-               }
-               else if(strstr(printNameStr, SSHv1_PUB_KEY_NAME) == printNameStr) {
-                       toStrip = strlen(SSHv1_PUB_KEY_NAME);
-               }
-               else if(strstr(printNameStr, SSHv1_PRIV_KEY_NAME) == printNameStr) {
-                       toStrip = strlen(SSHv1_PRIV_KEY_NAME);
-               }
-               if(toStrip) {
-                       /* only strip if we have ": " after toStrip bytes */
-                       if((printNameStr[toStrip] == ':') && (printNameStr[toStrip+1] == ' ')) {
-                               toStrip += 2;
-                       }
-               }
-       }
-       if(printNameStr) {
-               free(printNameStr);
-       }
-       len = attr->length;
-
-       unsigned char *attrVal;
-
-       if(len < toStrip) {
-               SecSSHDbg("impExpOpensshInferDescData: string parse screwup");
-               goto errOut;
-       }
-       if(len > toStrip) {
-               /* Normal case of stripping off leading header */
-               len -= toStrip;
-       }
-       else {
-               /* 
-                * If equal, then the attr value *is* "OpenSSHv2 Public Key: " with 
-                * no comment. Not sure how that could happen, but let's be careful.
-                */
-               toStrip = 0;
-       }
-       
-       attrVal = ((unsigned char *)attr->data) + toStrip;
-       descData.copy(attrVal, len);
-errOut:
-       SecKeychainItemFreeAttributesAndData(attrList, NULL);
-       return;
-}
-
-#pragma mark --- Derive SSHv1 wrap/unwrap key ---
-
-/* 
- * Common code to derive a wrap/unwrap key for OpenSSHv1.
- * Caller must CSSM_FreeKey when done.
- */
-static CSSM_RETURN openSSHv1DeriveKey(
-       CSSM_CSP_HANDLE         cspHand,
-       const SecKeyImportExportParameters      *keyParams,             // required 
-       impExpVerifyPhrase  verifyPhrase,                                       // for secure passphrase
-       CSSM_KEY_PTR            symKey)                                                 // RETURNED
-{
-       CSSM_KEY                                        *passKey = NULL;
-       CFDataRef                                       cfPhrase = NULL;
-       CSSM_RETURN                                     crtn;
-       OSStatus                                        ortn;
-       CSSM_DATA                                       dummyLabel;
-       uint32                                          keyAttr;
-       CSSM_CC_HANDLE                          ccHand = 0;
-       CSSM_ACCESS_CREDENTIALS         creds;
-       CSSM_CRYPTO_DATA                        seed;
-       CSSM_DATA                                       nullParam = {0, NULL};
-       
-       memset(symKey, 0, sizeof(CSSM_KEY));
-       
-       /* passphrase or passkey? */
-       ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, verifyPhrase,
-               (CFTypeRef *)&cfPhrase, &passKey);
-       if(ortn) {
-               return ortn;
-       }
-       /* subsequent errors to errOut: */
-
-       memset(&seed, 0, sizeof(seed));
-       if(cfPhrase != NULL) {
-               /* TBD - caller-supplied empty passphrase means "export in the clear" */
-               size_t len = CFDataGetLength(cfPhrase);
-               seed.Param.Data = (uint8 *)malloc(len);
-               seed.Param.Length = len;
-               memmove(seed.Param.Data, CFDataGetBytePtr(cfPhrase), len);
-               CFRelease(cfPhrase);
-       }
-
-       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
-       crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
-               CSSM_ALGID_OPENSSH1,
-               CSSM_ALGID_OPENSSH1,
-               CC_MD5_DIGEST_LENGTH * 8,
-               &creds,
-               passKey,                // BaseKey
-               0,                              // iterationCount
-               NULL,                   // salt
-               &seed,
-               &ccHand);
-       if(crtn) {
-               SecSSHDbg("openSSHv1DeriveKey CSSM_CSP_CreateDeriveKeyContext failure");
-               goto errOut;
-       }
-       
-       /* not extractable even for the short time this key lives */
-       keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE;
-       dummyLabel.Data = (uint8 *)"temp unwrap key";
-       dummyLabel.Length = strlen((char *)dummyLabel.Data);
-       
-       crtn = CSSM_DeriveKey(ccHand,
-               &nullParam,
-               CSSM_KEYUSE_ANY,
-               keyAttr,
-               &dummyLabel,
-               NULL,                   // cred and acl
-               symKey);
-       if(crtn) {
-               SecSSHDbg("openSSHv1DeriveKey CSSM_DeriveKey failure");
-       }
-errOut:
-       if(ccHand != 0) {
-               CSSM_DeleteContext(ccHand);
-       }
-       if(passKey != NULL) {
-               CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
-               free(passKey);
-       }
-       if(seed.Param.Data) {
-               memset(seed.Param.Data, 0, seed.Param.Length);
-               free(seed.Param.Data);
-       }
-       return crtn;
-}
-
-#pragma mark -- OpenSSHv1 Wrap/Unwrap ---
-
-/*
- * If cspHand is provided instead of importKeychain, the CSP 
- * handle MUST be for the CSPDL, not for the raw CSP.
- */
-OSStatus impExpWrappedOpenSSHImport(
-       CFDataRef                                                       inData,
-       SecKeychainRef                                          importKeychain, // optional
-       CSSM_CSP_HANDLE                                         cspHand,                // required
-       SecItemImportExportFlags                        flags,
-       const SecKeyImportExportParameters      *keyParams,             // optional 
-       const char                                                      *printName,
-       CFMutableArrayRef                                       outArray)               // optional, append here 
-{
-       OSStatus                                ortn;
-       impExpKeyUnwrapParams   unwrapParams;
-
-       assert(cspHand != 0);
-       if(keyParams == NULL) {
-               return errSecParam;
-       }
-       memset(&unwrapParams, 0, sizeof(unwrapParams));
-
-       /* derive unwrapping key */
-       CSSM_KEY unwrappingKey;
-       
-       ortn = openSSHv1DeriveKey(cspHand, keyParams, VP_Import, &unwrappingKey);
-       if(ortn) {
-               return ortn;
-       }
-       
-       /* set up key to unwrap */
-       CSSM_KEY                                wrappedKey;
-       CSSM_KEYHEADER                  &hdr = wrappedKey.KeyHeader;
-       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-       hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
-       /* CspId : don't care */
-       hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
-       hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1;
-       hdr.AlgorithmId = CSSM_ALGID_RSA;               /* the oly algorithm supported in SSHv1 */
-       hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
-       /* LogicalKeySizeInBits : calculated by CSP during unwrap */
-       hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
-       hdr.KeyUsage = CSSM_KEYUSE_ANY;
-
-       wrappedKey.KeyData.Data = (uint8 *)CFDataGetBytePtr(inData);
-       wrappedKey.KeyData.Length = CFDataGetLength(inData);
-       
-       unwrapParams.unwrappingKey = &unwrappingKey;
-       unwrapParams.encrAlg = CSSM_ALGID_OPENSSH1;
-       
-       /* GO */
-       ortn =  impExpImportKeyCommon(&wrappedKey, importKeychain, cspHand,
-               flags, keyParams, &unwrapParams, printName, outArray);
-               
-       if(unwrappingKey.KeyData.Data != NULL) {
-               CSSM_FreeKey(cspHand, NULL, &unwrappingKey, CSSM_FALSE);
-       }
-       return ortn;
-}
-
-OSStatus impExpWrappedOpenSSHExport(
-       SecKeyRef                                                       secKey,
-       SecItemImportExportFlags                        flags,          
-       const SecKeyImportExportParameters      *keyParams,             // optional 
-       const CssmData                                          &descData,
-       CFMutableDataRef                                        outData)                // output appended here
-{
-       CSSM_CSP_HANDLE cspdlHand = 0;
-       OSStatus ortn;
-       bool releaseCspHand = false;
-       CSSM_RETURN crtn;
-       
-       if(keyParams == NULL) {
-               return errSecParam;
-       }
-
-       /* we need a CSPDL handle - try to get it from the key */       
-       ortn = SecKeyGetCSPHandle(secKey, &cspdlHand);
-       if(ortn) {
-               cspdlHand = cuCspStartup(CSSM_FALSE);
-               if(cspdlHand == 0) {
-                       return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
-               }
-               releaseCspHand = true;
-       }
-       /* subsequent errors to errOut: */
-
-       /* derive wrapping key */
-       CSSM_KEY wrappingKey;
-       crtn = openSSHv1DeriveKey(cspdlHand, keyParams, VP_Export, &wrappingKey);
-       if(crtn) {
-               goto errOut;
-       }
-       
-       /* GO */
-       CSSM_KEY wrappedKey;
-       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
-       
-       crtn = impExpExportKeyCommon(cspdlHand, secKey, &wrappingKey, &wrappedKey,
-               CSSM_ALGID_OPENSSH1, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE,
-               CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1, CSSM_ATTRIBUTE_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE, 
-               &descData,
-               NULL);  // IV
-       if(crtn) {
-               goto errOut;
-       }
-       
-       /* the wrappedKey's KeyData is out output */
-       CFDataAppendBytes(outData, wrappedKey.KeyData.Data, wrappedKey.KeyData.Length);
-       CSSM_FreeKey(cspdlHand, NULL, &wrappedKey, CSSM_FALSE);
-       
-errOut:
-       if(releaseCspHand) {
-               cuCspDetachUnload(cspdlHand, CSSM_FALSE);
-       }
-       return crtn;
-
-}