Fixed: <rdar://problem/3674867> use new Security framework SPI's to reenable cert...
authorcblu <cblu@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Aug 2004 23:36:44 +0000 (23:36 +0000)
committercblu <cblu@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 23 Aug 2004 23:36:44 +0000 (23:36 +0000)
        Reviewed by john.

        * WebCoreSupport.subproj/WebKeyGeneration.cpp:
        * WebCoreSupport.subproj/WebKeyGeneration.h:
        * WebCoreSupport.subproj/WebKeyGenerator.h:
        * WebCoreSupport.subproj/WebKeyGenerator.m:
        (-[WebKeyGenerator signedPublicKeyAndChallengeStringWithStrengthIndex:challenge:pageURL:]): re-enabled cert code, call Panther version on Panther, Tiger version on Tiger
        (-[WebKeyGenerator addCertificatesToKeychainFromData:]): ditto
        * WebCoreSupport.subproj/WebNewKeyGeneration.c: Added.
        (gnrAddContextAttribute):
        (gnrGetSubjPubKey):
        (gnrNullAlgParams):
        (gnrSign):
        (gnrFreeCssmData):
        (nssArraySize):
        (signedPublicKeyAndChallengeString):
        (addCertificateToKeychainFromData):
        (addCertificatesToKeychainFromData):
        * WebCoreSupport.subproj/WebNewKeyGeneration.h: Added.
        * WebKit.pbproj/project.pbxproj:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7328 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebKeyGeneration.cpp
WebKit/WebCoreSupport.subproj/WebKeyGeneration.h
WebKit/WebCoreSupport.subproj/WebKeyGenerator.h
WebKit/WebCoreSupport.subproj/WebKeyGenerator.m
WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.c [new file with mode: 0644]
WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.h [new file with mode: 0644]
WebKit/WebKit.pbproj/project.pbxproj

index 711ab2d34e70447bf9de9c2821ba910dd1869379..cbcedadadf574067509e478a384188771dff1e82 100644 (file)
@@ -1,3 +1,28 @@
+2004-08-23  Chris Blumenberg  <cblu@apple.com>
+
+       Fixed: <rdar://problem/3674867> use new Security framework SPI's to reenable cert acquisition
+
+        Reviewed by john.
+
+        * WebCoreSupport.subproj/WebKeyGeneration.cpp:
+        * WebCoreSupport.subproj/WebKeyGeneration.h:
+        * WebCoreSupport.subproj/WebKeyGenerator.h:
+        * WebCoreSupport.subproj/WebKeyGenerator.m:
+        (-[WebKeyGenerator signedPublicKeyAndChallengeStringWithStrengthIndex:challenge:pageURL:]): re-enabled cert code, call Panther version on Panther, Tiger version on Tiger
+        (-[WebKeyGenerator addCertificatesToKeychainFromData:]): ditto
+        * WebCoreSupport.subproj/WebNewKeyGeneration.c: Added.
+        (gnrAddContextAttribute):
+        (gnrGetSubjPubKey):
+        (gnrNullAlgParams):
+        (gnrSign):
+        (gnrFreeCssmData):
+        (nssArraySize):
+        (signedPublicKeyAndChallengeString):
+        (addCertificateToKeychainFromData):
+        (addCertificatesToKeychainFromData):
+        * WebCoreSupport.subproj/WebNewKeyGeneration.h: Added.
+        * WebKit.pbproj/project.pbxproj:
+
 2004-08-20  David Hyatt  <hyatt@apple.com>
 
        Fix the directionality of the unicode hyphen so that on Panther it now matches Tiger.
index 6bf0630d982d818548d4e717216e886b42b8a67d..282c08635dc73cabb0c707f9ccd2e4a80ebd9104 100644 (file)
@@ -9,7 +9,7 @@
 
 #import <WebKit/WebKeyGeneration.h>
 
-#ifndef DISABLE_WEB_KEY_GENERATION
+#ifndef USE_NEW_KEY_GENERATION
 
 #import <WebKit/WebAssertions.h>
 
@@ -683,4 +683,4 @@ WebCertificateParseResult addCertificatesToKeychainFromData(const void *bytes, u
     return result;
 }
 
-#endif /* DISABLE_WEB_KEY_GENERATION */
+#endif /* USE_NEW_KEY_GENERATION */
index 7ae84054015e0ec11cd4f3b29e9f6d7f22c9dbc5..eca142a9f6bb1ccfbc89bbd7485e4075b8e49504 100644 (file)
 #ifndef        WEB_KEY_GENERATION_H
 #define WEB_KEY_GENERATION_H
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3
-#define DISABLE_WEB_KEY_GENERATION
-#endif
-
-#ifndef DISABLE_WEB_KEY_GENERATION
-
 #import <WebKit/WebKeyGenerator.h>
 
+#ifndef USE_NEW_KEY_GENERATION
+
 #import <CoreFoundation/CoreFoundation.h>
 
 #include <SecurityNssAsn1/secasn1t.h>
@@ -84,6 +80,6 @@ extern "C" {
 }
 #endif
 
-#endif /* DISABLE_WEB_KEY_GENERATION */
+#endif /* USE_NEW_KEY_GENERATION */
 
 #endif /* WEB_KEY_GENERATION_H */
index 377a6e4045d469db4e3b0f7a11228b30caca838f..2eb19c3ac8cb3150d8a3667e25cd838f5394c5ed 100644 (file)
@@ -6,6 +6,10 @@
 //  Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
 //
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_3
+#define USE_NEW_KEY_GENERATION
+#endif
+
 typedef enum {
     WebCertificateParseResultSucceeded  = 0,
     WebCertificateParseResultFailed     = 1,
index 41523cce02692ced3bd2cbe90ecfaa65d69177a5..fb2b678840de24b87a058ada271fbce53233027d 100644 (file)
@@ -9,9 +9,14 @@
 #import <WebKit/WebKeyGenerator.h>
 
 #import <WebKit/WebAssertions.h>
-#import <WebKit/WebKeyGeneration.h>
 #import <WebKit/WebLocalizableStrings.h>
 
+#ifdef USE_NEW_KEY_GENERATION
+#import <WebKit/WebNewKeyGeneration.h>
+#else 
+#import <WebKit/WebKeyGeneration.h>
+#endif
+
 @implementation WebKeyGenerator
 
 + (void)createSharedGenerator
             return nil;
     }
     
-#ifdef DISABLE_WEB_KEY_GENERATION
-       return nil;
-#else 
-       NSString *keyDescription = [NSString stringWithFormat:UI_STRING("Key from %@", "name of keychain key generated by the KEYGEN tag"), [pageURL host]];
+    NSString *keyDescription = [NSString stringWithFormat:UI_STRING("Key from %@", "name of keychain key generated by the KEYGEN tag"), [pageURL host]];
     return [(NSString *)signedPublicKeyAndChallengeString(keySize, (CFStringRef)challenge, (CFStringRef)keyDescription) autorelease];
-#endif 
 }
 
 - (WebCertificateParseResult)addCertificatesToKeychainFromData:(NSData *)data
 {
-#ifdef DISABLE_WEB_KEY_GENERATION
-       return WebCertificateParseResultFailed;
-#else 
     return addCertificatesToKeychainFromData([data bytes], [data length]);
-#endif
 }
 
 @end
diff --git a/WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.c b/WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.c
new file mode 100644 (file)
index 0000000..d811706
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ *  WebNewKeyGeneration.cpp
+ *  WebKit
+ *
+ *  Created by Chris Blumenberg on Mon Aug 23 2004.
+ *  Copyright (c) 2003 Apple Computer. All rights reserved.
+ *
+ */
+
+#import <WebKit/WebNewKeyGeneration.h>
+
+#ifdef USE_NEW_KEY_GENERATION
+
+#import <WebKit/WebAssertions.h>
+
+#import <Security/keyTemplates.h>
+#import <Security/SecKeyPriv.h>                /* Security.framework SPI */
+
+#import <security_cdsa_utils/cuEnc64.h>
+
+/* hard coded params, some of which may come from the user in real life */
+#define GNR_KEY_ALG                    CSSM_ALGID_RSA
+#define GNR_SIG_ALG                    CSSM_ALGID_MD5WithRSA
+#define GNR_SIG_ALGOID                  CSSMOID_MD5WithRSA
+
+const SecAsn1Template NetscapeCertSequenceTemplate[] = {
+{ SEC_ASN1_SEQUENCE,
+    0, NULL, sizeof(NetscapeCertSequence) },
+{ SEC_ASN1_OBJECT_ID,
+    offsetof(NetscapeCertSequence, contentType), 0, 0 },
+{ SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | 
+    SEC_ASN1_CONTEXT_SPECIFIC | 0 , 
+    offsetof(NetscapeCertSequence, certs),
+    kSecAsn1SequenceOfAnyTemplate, 0 },
+{ 0, 0, 0, 0 }
+};
+
+const SecAsn1Template PublicKeyAndChallengeTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+        0, NULL, sizeof(PublicKeyAndChallenge) },
+    { SEC_ASN1_INLINE,
+        offsetof(PublicKeyAndChallenge, spki),
+        kSecAsn1SubjectPublicKeyInfoTemplate, 0},
+    { SEC_ASN1_INLINE,
+        offsetof(PublicKeyAndChallenge, challenge),
+        kSecAsn1IA5StringTemplate, 0 },
+    { 0, 0, 0, 0}
+};
+
+const SecAsn1Template SignedPublicKeyAndChallengeTemplate[] = {
+    { SEC_ASN1_SEQUENCE,
+        0, NULL, sizeof(SignedPublicKeyAndChallenge) },
+    { SEC_ASN1_INLINE,
+        offsetof(SignedPublicKeyAndChallenge, pubKeyAndChallenge),
+        PublicKeyAndChallengeTemplate, 0 },
+    { SEC_ASN1_INLINE,
+        offsetof(SignedPublicKeyAndChallenge, algId),
+        kSecAsn1AlgorithmIDTemplate, 0 },
+    { SEC_ASN1_BIT_STRING,
+        offsetof(SignedPublicKeyAndChallenge, signature), 0, 0 },
+    { 0, 0, 0, 0 }
+};
+
+void gnrNullAlgParams(CSSM_X509_ALGORITHM_IDENTIFIER *algId);
+CSSM_RETURN gnrSign(CSSM_CSP_HANDLE            cspHand,
+                    const CSSM_DATA            *plainText,
+                    SecKeyRef                  privKey,
+                    CSSM_ALGORITHMS            sigAlg,         // e.g., CSSM_ALGID_SHA1WithRSA
+                    CSSM_DATA                  *sig);
+unsigned nssArraySize(const void **array);
+bool addCertificateToKeychainFromData(const unsigned char *certData,
+                                      unsigned certDataLen,
+                                      unsigned certNum);
+
+/*
+ * Given a context specified via a CSSM_CC_HANDLE, add a new
+ * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
+ * AttributeLength, and an untyped pointer.
+ *
+ * This is currently used to add a second CSSM_KEY attribute when performing
+ * ops with algorithm CSSM_ALGID_FEED and CSSM_ALGID_FEECFILE.
+ */
+static CSSM_RETURN gnrAddContextAttribute(CSSM_CC_HANDLE CCHandle,
+                                          uint32 AttributeType,
+                                          uint32 AttributeLength,
+                                          const void *AttributePtr)
+{
+    CSSM_CONTEXT_ATTRIBUTE             newAttr;        
+    CSSM_RETURN                                        crtn;
+    
+    newAttr.AttributeType     = AttributeType;
+    newAttr.AttributeLength   = AttributeLength;
+    newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
+    crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
+    if(crtn) {
+        ERROR("CSSM_UpdateContextAttributes", crtn);
+    }
+    return crtn;
+}
+
+/*
+ * Given a public key as a SecKeyRef, obtain the key material in
+ * SubjectPublicKeyInfo format. This entails a NULL wrap to format
+ * in CSSM_KEYBLOB_RAW_FORMAT_X509 form. Caller must eventually
+ * free the returned key via CSSM_FreeKey().
+ */
+static OSStatus gnrGetSubjPubKey(
+                                 CSSM_CSP_HANDLE       cspHand,
+                                 SecKeyRef secKey,
+                                 CSSM_KEY_PTR subjPubKey)              // RETURNED
+{
+    CSSM_CC_HANDLE             ccHand;
+    CSSM_RETURN                        crtn;
+    CSSM_ACCESS_CREDENTIALS    creds;
+    const CSSM_KEY             *refPubKey;
+    OSStatus                   ortn;
+    
+    /* Get public key in CSSM form */
+    ortn = SecKeyGetCSSMKey(secKey, &refPubKey);
+    if(ortn) {
+        ERROR("SecKeyGetCSSMKey", ortn);
+        return ortn;
+    }
+    
+    /* NULL wrap via CSPDL */
+    memset(subjPubKey, 0, sizeof(CSSM_KEY));
+    memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+    crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+                                           CSSM_ALGID_NONE,
+                                           CSSM_ALGMODE_NONE,
+                                           &creds,                             // passPhrase
+                                           NULL,                               // wrapping key
+                                           NULL,                               // init vector
+                                           CSSM_PADDING_NONE,  // Padding
+                                           0,                                  // Params
+                                           &ccHand);
+    if(crtn) {
+        ERROR("gnrGetSubjPubKey CSSM_CSP_CreateSymmetricContext", 
+                     crtn);
+        return crtn;
+    }
+    
+    /*
+     * Specify X509 format' that is NOT the default for RSA (PKCS1 is)
+     */
+    crtn = gnrAddContextAttribute(ccHand,
+                                  CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
+                                  sizeof(uint32),
+                                  (void *)CSSM_KEYBLOB_RAW_FORMAT_X509);
+    if(crtn) {
+        ERROR("gnrAddContextAttribute", crtn);
+        goto errOut;
+    }
+    
+    crtn = CSSM_WrapKey(ccHand,
+                        &creds,
+                        refPubKey,
+                        NULL,                  // DescriptiveData
+                        subjPubKey);
+    if(crtn) {
+        ERROR("CSSM_WrapKey", crtn);
+    }
+errOut:
+        CSSM_DeleteContext(ccHand);
+    return crtn;
+}
+
+/* 
+* Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters.
+ */
+void gnrNullAlgParams(CSSM_X509_ALGORITHM_IDENTIFIER *algId)
+{
+    static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 };
+    algId->parameters.Data = (uint8 *)encNull;
+    algId->parameters.Length = 2;
+}
+
+/*
+ * Sign specified plaintext. Caller must free signature data via
+ * gnrFreeCssmData().
+ */
+CSSM_RETURN gnrSign(CSSM_CSP_HANDLE            cspHand,
+                    const CSSM_DATA            *plainText,
+                    SecKeyRef                  privKey,
+                    CSSM_ALGORITHMS            sigAlg,         // e.g., CSSM_ALGID_SHA1WithRSA
+                    CSSM_DATA                  *sig)           // allocated by CSP and RETURNED
+{
+    CSSM_CC_HANDLE             ccHand;
+    CSSM_RETURN                        crtn;
+    const CSSM_KEY             *refPrivKey;
+    OSStatus                   ortn;
+    const CSSM_ACCESS_CREDENTIALS *creds;
+    
+    /* Get private key in CSSM form */
+    ortn = SecKeyGetCSSMKey(privKey, &refPrivKey);
+    if(ortn) {
+        ERROR("SecKeyGetCSSMKey", ortn);
+        return ortn;
+    }
+    
+    /* Get appropriate access credentials */
+    ortn = SecKeyGetCredentials(privKey,
+                                CSSM_ACL_AUTHORIZATION_SIGN,
+                                kSecCredentialTypeDefault,
+                                &creds);
+    if(ortn) {
+        ERROR("SecKeyGetCredentials", ortn);
+        return ortn;
+    }
+    
+    /* cook up signature context */
+    crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+                                           sigAlg,
+                                           creds,      
+                                           refPrivKey,
+                                           &ccHand);
+    if(crtn) {
+        ERROR("CSSM_CSP_CreateSignatureContext", ortn);
+        return crtn;
+    }
+    
+    /* go for it */
+    sig->Data = NULL;
+    sig->Length = 0;
+    crtn = CSSM_SignData(ccHand,
+                         plainText,
+                         1,
+                         CSSM_ALGID_NONE,
+                         sig);
+    if(crtn) {
+        ERROR("CSSM_SignData", ortn);
+    }
+    CSSM_DeleteContext(ccHand);
+    return crtn;
+}
+
+/*
+ * Free data mallocd on app's behalf by a CSSM module.
+ */
+static void gnrFreeCssmData(
+                            CSSM_HANDLE                modHand,
+                            CSSM_DATA          *cdata)
+{
+    CSSM_API_MEMORY_FUNCS memFuncs;
+    CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(modHand, &memFuncs);
+    if(crtn) {
+        ERROR("CSSM_GetAPIMemoryFunctions", crtn);
+        /* oh well, leak and continue */
+    }
+    else {
+        memFuncs.free_func(cdata->Data, memFuncs.AllocRef);
+    }
+    return;
+}
+
+unsigned nssArraySize(const void **array)
+{
+    unsigned count = 0;
+    if (array) {
+        while (*array++) {
+            count++;
+        }
+    }
+    return count;
+}
+
+CFStringRef signedPublicKeyAndChallengeString(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription)
+{
+    OSStatus           ortn;
+    CSSM_RETURN                crtn;
+    SecKeyRef          pubKey = NULL;
+    SecKeyRef          privKey = NULL;
+    CSSM_KEY           subjectPubKey;
+    bool                freeSubjPubKey = false;
+    CSSM_CSP_HANDLE    cspHand;
+    SecAsn1CoderRef     coder = NULL;
+    SignedPublicKeyAndChallenge        spkc;
+    PublicKeyAndChallenge              *pkc = &spkc.pubKeyAndChallenge;
+    /* DER encoded spkc.pubKeyAndChallenge and spkc */
+    CSSM_DATA          encodedPkc = {0, NULL};         
+    CSSM_DATA          encodedSpkc = {0, NULL};
+    CSSM_DATA          signature = {0, NULL};
+    unsigned char      *spkcB64 = NULL;                // base64 encoded encodedSpkc
+    unsigned           spkcB64Len;
+    SecAccessRef        accessRef;
+    CFArrayRef          acls;
+    SecACLRef           acl;
+    CFStringRef         result = NULL;
+    
+    ortn = SecAccessCreate(keyDescription, NULL, &accessRef);
+    if (ortn) {
+        ERROR("***SecAccessCreate %d", ortn);
+        goto errOut;
+    }
+    ortn = SecAccessCopySelectedACLList(accessRef, CSSM_ACL_AUTHORIZATION_DECRYPT, &acls);
+    if (ortn) {
+        ERROR("***SecAccessCopySelectedACLList %d", ortn);
+        goto errOut;
+    }
+    acl = (SecACLRef)CFArrayGetValueAtIndex(acls, 0);
+    CFRelease(acls);
+    ortn = SecACLSetSimpleContents(acl, NULL, keyDescription, NULL);
+    if (ortn) {
+        ERROR("***SecACLSetSimpleContents %d", ortn);
+        goto errOut;
+    }
+    
+    // Cook up a key pair, just use any old params for now
+    ortn = SecKeyCreatePair(nil,                                        // in default KC
+                            GNR_KEY_ALG,                                // normally spec'd by user
+                            keySize,                                    // key size, ditto
+                            0,                                          // ContextHandle
+                            CSSM_KEYUSE_ANY,                            // might want to restrict this
+                            CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE | 
+                            CSSM_KEYATTR_RETURN_REF,                    // pub attrs
+                            CSSM_KEYUSE_ANY,                           // might want to restrict this
+                            CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF |
+                            CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE,
+                            accessRef,
+                            &pubKey,
+                            &privKey);
+    if (ortn != noErr) {
+        ERROR("***SecKeyCreatePair %d", ortn);
+        goto errOut;
+    }
+    
+    /* get handle of CSPDL for crypto ops */
+    ortn = SecKeyGetCSPHandle(privKey, &cspHand);
+    if (ortn != noErr) {
+        ERROR("***SecKeyGetCSPHandle", ortn);
+        goto errOut;
+    }
+    
+    /*
+     * Get the public key in encoded SubjectPublicKeyInfo form.
+     */
+    ortn = gnrGetSubjPubKey(cspHand, pubKey, &subjectPubKey);
+    if (ortn != noErr) {
+        goto errOut;
+    }
+    freeSubjPubKey = true;
+    
+    ortn = SecAsn1CoderCreate(&coder);
+    if (ortn != noErr) {
+        ERROR("***SecAsn1CoderCreate", ortn);
+        goto errOut;
+    }
+    
+    /*
+     * Cook up PublicKeyAndChallenge and DER-encode it.
+     * First, DER-decode the key's SubjectPublicKeyInfo.
+     */
+    memset(&spkc, 0, sizeof(spkc));
+    
+    ortn = SecAsn1DecodeData(coder, &subjectPubKey.KeyData, kSecAsn1SubjectPublicKeyInfoTemplate, &pkc->spki);
+    if (ortn != noErr) {
+        /* should never happen */
+        ERROR("***Error decoding subject public key info\n");
+        goto errOut;
+    }
+    
+    pkc->challenge.Length = CFStringGetLength(challenge);
+    if (pkc->challenge.Length == 0) {
+        pkc->challenge.Length = 1;
+        pkc->challenge.Data = (uint8 *)strdup("\0");
+    } else {
+        pkc->challenge.Data = (uint8 *)malloc(pkc->challenge.Length + 1);
+        CFStringGetCString(challenge,  (char *)pkc->challenge.Data, pkc->challenge.Length + 1, kCFStringEncodingASCII);
+    }
+    ortn = SecAsn1EncodeItem(coder, pkc, PublicKeyAndChallengeTemplate, &encodedPkc);
+    if (ortn != noErr) {
+        /* should never happen */
+        ERROR("***Error encoding PublicKeyAndChallenge\n");
+        goto errOut;
+    }
+    
+    /*
+     * Sign the encoded PublicKeyAndChallenge.
+     */
+    crtn = gnrSign(cspHand, &encodedPkc, privKey, GNR_SIG_ALG, &signature);
+    if (crtn) {
+        goto errOut;
+    }
+    
+    /*
+     * Cook up SignedPublicKeyAndChallenge, DER-encode that. 
+     * The PublicKeyAndChallenge stays in place where we originally
+     * created it before we signed it. Now we just add the algId
+     * and the signature proper.
+     */
+    spkc.algId.algorithm = GNR_SIG_ALGOID;
+    gnrNullAlgParams(&spkc.algId);
+    spkc.signature = signature;
+    /* convert to BIT length */
+    spkc.signature.Length *= 8;
+    ortn = SecAsn1EncodeItem(coder, &spkc, SignedPublicKeyAndChallengeTemplate, &encodedSpkc);
+    if (ortn != noErr) {
+        /* should never happen */
+        ERROR("***Error encoding SignedPublicKeyAndChallenge\n");
+        goto errOut;
+    }
+    
+    /*
+     * Finally base64 the result and write that to outFile.
+     * cuEnc64() gives us a NULL-terminated string; we strip off the NULL.
+     */
+    spkcB64 = cuEnc64(encodedSpkc.Data, encodedSpkc.Length, &spkcB64Len);
+    if (spkcB64 == NULL) {
+        /* should never happen */
+        FATAL("***Error base64-encoding the result\n");
+        goto errOut;
+    }
+    
+errOut:
+    if (coder != NULL) {
+        SecAsn1CoderRelease(coder);
+    }
+    if (freeSubjPubKey) {
+        CSSM_FreeKey(cspHand, NULL, &subjectPubKey, CSSM_FALSE);
+    }
+    if (signature.Data) {
+        gnrFreeCssmData(cspHand, &signature);
+    }
+    if (pubKey) {
+        CFRelease(pubKey);
+    }
+    if (privKey) {
+        CFRelease(privKey);
+    }
+    if (accessRef) {
+        CFRelease(accessRef);
+    }    
+    if (pkc->challenge.Data) {
+        free(pkc->challenge.Data);
+    }
+    if (spkcB64) {
+        result = CFStringCreateWithCString(NULL, (const char *)spkcB64, kCFStringEncodingASCII);
+        free(spkcB64);
+    }
+    return result;
+}
+
+/* 
+* Per-cert processing, called for each cert we extract from the 
+ * incoming blob.
+ */
+bool addCertificateToKeychainFromData(const unsigned char *certData,
+                                      unsigned certDataLen,
+                                      unsigned certNum)
+{
+    CSSM_DATA cert = {certDataLen, (uint8 *)certData};
+    SecCertificateRef certRef;
+    
+    /* Make a SecCertificateRef */
+    OSStatus ortn = SecCertificateCreateFromData(&cert, 
+                                                 CSSM_CERT_X_509v3,
+                                                 CSSM_CERT_ENCODING_DER,
+                                                 &certRef);
+    if (ortn != noErr) {
+        ERROR("SecCertificateCreateFromData returned %d", (int)ortn);
+        return false;
+    }
+    
+    /* 
+        * Add it to default keychain.
+        * Many people will be surprised that this op works without
+        * the user having to unlock the keychain. 
+        */
+    ortn = SecCertificateAddToKeychain(certRef, nil);
+    
+    /* Free the cert in any case */
+    CFRelease(certRef);
+    switch(ortn) {
+        case noErr:
+            break;
+        case errSecDuplicateItem:
+            /* Not uncommon, definitely not an error */
+            ERROR("cert %u already present in keychain", certNum);
+            break;
+        default:
+            ERROR("SecCertificateAddToKeychain returned %d", (int)ortn);
+            return false;
+    }
+
+    return true;
+}
+
+WebCertificateParseResult addCertificatesToKeychainFromData(const void *bytes, unsigned length)
+{   
+    WebCertificateParseResult result = WebCertificateParseResultFailed;
+
+    /* DER-decode, first as NetscapeCertSequence */
+    SecAsn1CoderRef coder = NULL;
+    NetscapeCertSequence certSeq;
+    OSErr ortn;
+    
+    ortn = SecAsn1CoderCreate(&coder);
+    if (ortn == noErr) {
+        memset(&certSeq, 0, sizeof(certSeq));
+        ortn = SecAsn1Decode(coder, bytes, length, NetscapeCertSequenceTemplate, &certSeq);
+        if (ortn == noErr) {
+            if (certSeq.contentType.Length == CSSMOID_PKCS7_SignedData.Length &&
+                memcmp(certSeq.contentType.Data, CSSMOID_PKCS7_SignedData.Data, certSeq.contentType.Length) == 0) {
+                return WebCertificateParseResultPKCS7;
+            }
+            /*
+             * Last cert is a root, which we do NOT want to add
+             * to the user's keychain.
+             */
+            unsigned numCerts = nssArraySize((const void **)certSeq.certs) - 1;
+            unsigned i;
+            for (i=0; i<numCerts; i++) {
+                CSSM_DATA *cert = certSeq.certs[i];
+                result = addCertificateToKeychainFromData(cert->Data, cert->Length, i) ? WebCertificateParseResultSucceeded : WebCertificateParseResultFailed;
+            } 
+        } else {
+            /*
+             * Didn't appear to be a NetscapeCertSequence; assume it's just 
+             * a cert. FIXME: Netscape spec says the blob might also be PKCS7
+             * format, which we're not handling here.
+             */
+            result = addCertificateToKeychainFromData(bytes, length, 0) ? WebCertificateParseResultSucceeded : WebCertificateParseResultFailed;
+        }
+    }
+    
+    if (coder != NULL) {
+        SecAsn1CoderRelease(coder);
+    }
+
+    return result;
+}
+
+#endif /* USE_NEW_KEY_GENERATION */
diff --git a/WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.h b/WebKit/WebCoreSupport.subproj/WebNewKeyGeneration.h
new file mode 100644 (file)
index 0000000..e3ae9d1
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  WebNewKeyGeneration.h
+ *  WebKit
+ *
+ *  Created by Chris Blumenberg on Mon Aug 23 2004.
+ *  Copyright (c) 2003 Apple Computer. All rights reserved.
+ *
+ */
+
+#ifndef        WEB_KEY_GENERATION_H
+#define WEB_KEY_GENERATION_H
+
+#import <WebKit/WebKeyGenerator.h>
+
+#ifdef USE_NEW_KEY_GENERATION
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import <Security/asn1Templates.h>
+#import <Security/SecAsn1Coder.h>
+#import <Security/secasn1t.h>
+#import <Security/Security.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+    /* 
+    * Netscape Certifiate Sequence is defined by Netscape as a PKCS7
+     * ContentInfo with a contentType of netscape-cert-sequence and a content
+     * consisting of a sequence of certificates.
+     *
+     * For simplicity - i.e., to avoid the general purpose ContentInfo
+     * polymorphism - we'll just hard-code this particular type right here.
+     *
+     * Inside the ContentInfo is an array of standard X509 certificates.
+     * We don't need to parse the certs themselves so they remain as 
+     * opaque data blobs. 
+     */
+    typedef struct {
+        CSSM_OID               contentType;            // netscape-cert-sequence
+        CSSM_DATA              **certs;
+    } NetscapeCertSequence;
+    
+    extern const SecAsn1Template NetscapeCertSequenceTemplate[];
+    
+    /*
+     * Public key/challenge, to send to CA.
+     *
+     * PublicKeyAndChallenge ::= SEQUENCE {
+         *
+         * ¬†       spki SubjectPublicKeyInfo,
+         *     challenge IA5STRING
+         * }
+     *
+     * SignedPublicKeyAndChallenge ::= SEQUENCE {
+         *             publicKeyAndChallenge PublicKeyAndChallenge,
+         *             signatureAlgorithm AlgorithmIdentifier,
+         *             signature BIT STRING
+         * }
+     */
+    typedef struct {
+        CSSM_X509_SUBJECT_PUBLIC_KEY_INFO      spki;
+        CSSM_DATA                                                      challenge;      // ASCII
+    } PublicKeyAndChallenge;
+    
+    typedef struct {
+        PublicKeyAndChallenge                          pubKeyAndChallenge;
+        CSSM_X509_ALGORITHM_IDENTIFIER         algId;
+        CSSM_DATA                                                      signature; // length in BITS
+    } SignedPublicKeyAndChallenge;
+    
+    extern const SecAsn1Template PublicKeyAndChallengeTemplate[];
+    extern const SecAsn1Template SignedPublicKeyAndChallengeTemplate[];
+
+    CFStringRef signedPublicKeyAndChallengeString(unsigned keySize, CFStringRef challenge, CFStringRef keyDescription);
+    WebCertificateParseResult addCertificatesToKeychainFromData(const void *bytes, unsigned length);
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USE_NEW_KEY_GENERATION */
+
+#endif /* WEB_KEY_GENERATION_H */
index 942a10d6ab2bcfb32a56e59e74d3f28833e59afe..af73cca8b1dae8fb79613fd9fe00cd934fb0fe42 100644 (file)
                                6566F34204C12D14008B3232,
                        );
                        buildSettings = {
-                               COMMON_LDFLAGS = "-no-c++filt \"$OBJECT_FILE_DIR/WebKitSecurity.a\" -framework \"`if [ -f /System/Library/Frameworks/Quartz.framework/Quartz ]; then echo \\\"Quartz\\\"; else echo \\\"System\\\"; fi`\"";
+                               COMMON_LDFLAGS = "-no-c++filt \"$OBJECT_FILE_DIR/WebKitSecurity.a\" ${TIGER_FRAMEWORKS_LDFLAGS}";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_CFLAGS = "-DNDEBUG";
                                DYLIB_COMPATIBILITY_VERSION = 1;
                                DYLIB_CURRENT_VERSION = 1;
                                EXPORTED_SYMBOLS_FILE = WebKit.exp;
-                               FRAMEWORK_SEARCH_PATHS = "\"${DSTROOT}\" \"${MERGE_DIR}/${SYSTEM_LIBRARY_DIR}/Frameworks\" \"${MERGE_DIR}/$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\" ";
+                               FRAMEWORK_SEARCH_PATHS = "\"${DSTROOT}\" \"${MERGE_DIR}/${SYSTEM_LIBRARY_DIR}/Frameworks\" \"${MERGE_DIR}/$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/Frameworks/Carbon.framework/Frameworks\" \"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\" /usr/local/SecurityPieces/Frameworks";
                                FRAMEWORK_VERSION = A;
                                HEADER_SEARCH_PATHS = "";
                                INSTALL_PATH = /System/Library/Frameworks;
                                PREFIX_HEADER = WebKitPrefix.h;
                                PRODUCT_NAME = WebKit;
                                SECTORDER_FLAGS = "-sectorder __TEXT __text /AppleInternal/OrderFiles/WebKit.order";
+                               TIGER_FRAMEWORKS_LDFLAGS = "-framework \"`if [ -f /System/Library/Frameworks/Quartz.framework/Quartz ]; then echo \\\"Quartz\\\"; else echo \\\"System\\\"; fi`\" -framework \"`if [ -f /usr/local/SecurityPieces/Frameworks/security_cdsa_utils.framework ]; then echo \\\"security_cdsa_utils\\\"; else echo \\\"System\\\"; fi`\"";
                                USE_GCC3_PFE_SUPPORT = YES;
                                WARNING_CFLAGS = "-Werror -Wall -W -Wcast-align -Wchar-subscripts -Wformat-security -Wmissing-format-attribute -Wmissing-prototypes -Wpointer-arith -Wwrite-strings -Wno-format-y2k -Wno-unused-parameter -Wbad-function-cast -Wmissing-declarations -Wnested-externs";
                                WARNING_CPLUSPLUSFLAGS = "-Werror -Wall -Wcast-align -Wchar-subscripts -Wformat-security -Wmissing-format-attribute -Wmissing-prototypes -Wpointer-arith -Wwrite-strings -Wno-format-y2k -Wno-unused-parameter";
                                9348903806C0040B007E7ACE,
                                51E94C3606C0321200A9B09E,
                                51E94C6A06C0347500A9B09E,
+                               83634A7406DA5ECD0026E290,
                        );
                        isa = PBXHeadersBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                                8373435D0624EE0D00F3B289,
                                51E94C3706C0321200A9B09E,
                                51E94C6B06C0347500A9B09E,
+                               83634A7306DA5ECD0026E290,
                        );
                        isa = PBXSourcesBuildPhase;
                        runOnlyForDeploymentPostprocessing = 0;
                        settings = {
                        };
                };
+               83634A7106DA5ECD0026E290 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.c;
+                       path = WebNewKeyGeneration.c;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               83634A7206DA5ECD0026E290 = {
+                       fileEncoding = 30;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = WebNewKeyGeneration.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               83634A7306DA5ECD0026E290 = {
+                       fileRef = 83634A7106DA5ECD0026E290;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               83634A7406DA5ECD0026E290 = {
+                       fileRef = 83634A7206DA5ECD0026E290;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
                83730F9803FB1E660004736E = {
                        fileEncoding = 4;
                        isa = PBXFileReference;
                                9345D4EB0365C5B2008635CE,
                                830E81830585375700AD0891,
                                830E81840585375700AD0891,
+                               83634A7206DA5ECD0026E290,
+                               83634A7106DA5ECD0026E290,
                                84723BE3056D719E0044BFEA,
                                84723BE4056D719E0044BFEA,
                                F5E0E10802BC45F8018635CA,