MYEncoder.m
author Jens Alfke <jens@mooseyard.com>
Tue Jun 09 23:58:03 2009 -0700 (2009-06-09)
changeset 24 6856e071d25a
parent 8 4c0eafa7b233
permissions -rw-r--r--
* More work on iPhone compatibility.
* Restored the signature-verification code to MYCertInfo, which I'd removed earlier. I now need it to verify self-signed certs, since the Security framework won't do it for me.
* Merged MYCertificate-iPhone.m into MYCertificate.m since there's more shared code now.
     1 //
     2 //  MYEncoder.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 1/16/08.
     6 //  Copyright 2008-2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYEncoder.h"
    10 #import "MYIdentity.h"
    11 #import "MYCrypto_Private.h"
    12 #import "Test.h"
    13 #import "MYErrorUtils.h"
    14 
    15 
    16 @implementation MYEncoder
    17 
    18 
    19 - (id) init
    20 {
    21     self = [super init];
    22     if (self != nil) {
    23         if( ! checksave(CMSEncoderCreate(&_encoder)) ) {
    24             [self release];
    25             return nil;
    26         }
    27     }
    28     return self;
    29 }
    30 
    31 - (void) dealloc
    32 {
    33     if(_encoder) CFRelease(_encoder);
    34     [super dealloc];
    35 }
    36 
    37 
    38 
    39 - (BOOL) addSigner: (MYIdentity*)signer
    40 {
    41     Assert(signer);
    42     return checksave( CMSEncoderAddSigners(_encoder, signer.identityRef) );
    43 }
    44 
    45 - (BOOL) addRecipient: (MYCertificate*)recipient
    46 {
    47     Assert(recipient);
    48     return checksave( CMSEncoderAddRecipients(_encoder, recipient.certificateRef) );
    49 }
    50 
    51 - (BOOL) addSupportingCert: (MYCertificate*)supportingCert
    52 {
    53     Assert(supportingCert);
    54     return checksave( CMSEncoderAddSupportingCerts(_encoder, supportingCert.certificateRef) );
    55 }
    56 
    57 - (BOOL) addTimestamp
    58 {
    59     return checksave( CMSEncoderAddSignedAttributes(_encoder, kCMSAttrSigningTime) );
    60 }
    61 
    62 
    63 - (NSError*) error
    64 {
    65     if( _error )
    66         return MYError(_error, NSOSStatusErrorDomain, 
    67                        @"%@", MYErrorName(NSOSStatusErrorDomain,_error));
    68     else
    69         return nil;
    70 }
    71 
    72 
    73 - (CMSCertificateChainMode) certificateChainMode
    74 {
    75     CMSCertificateChainMode mode;
    76     if( CMSEncoderGetCertificateChainMode(_encoder, &mode) == noErr )
    77         return mode;
    78     else
    79         return -1;
    80 }
    81 
    82 - (void) setCertificateChainMode: (CMSCertificateChainMode)mode
    83 {
    84     checksave( CMSEncoderSetCertificateChainMode(_encoder, mode) );
    85 }
    86 
    87 - (BOOL) hasDetachedContent
    88 {
    89     Boolean detached;
    90     return CMSEncoderGetHasDetachedContent(_encoder, &detached)==noErr && detached;
    91 }
    92 
    93 - (void) setHasDetachedContent: (BOOL)detached
    94 {
    95     checksave( CMSEncoderSetHasDetachedContent(_encoder, detached) );
    96 }
    97 
    98 - (NSData*) _dataFromFunction: (OSStatus (*)(CMSEncoderRef,CFDataRef*))function
    99 {
   100     CFDataRef data=NULL;
   101     if( checksave( (*function)(_encoder, &data) ) )
   102         return [(NSData*)CFMakeCollectable(data) autorelease];
   103     else
   104         return nil;
   105 }
   106 
   107 
   108 - (CSSM_OID) contentType
   109 {
   110    NSData *data = [self _dataFromFunction: &CMSEncoderCopyEncapsulatedContentType];
   111    return (CSSM_OID){data.length,(uint8*)data.bytes};
   112 }
   113 
   114 - (void) setContentType: (CSSM_OID)contentType
   115 {
   116     checksave( CMSEncoderSetEncapsulatedContentType(_encoder, &contentType) );
   117 }
   118 
   119 
   120 - (BOOL) addData: (NSData*)data
   121 {
   122     Assert(data);
   123     return ! _error && checksave( CMSEncoderUpdateContent(_encoder, data.bytes, data.length) );
   124 }
   125 
   126 
   127 - (NSData*) encodedData
   128 {
   129     if( ! _error )
   130         return [self _dataFromFunction: &CMSEncoderCopyEncodedContent];
   131     else
   132         return nil;
   133 }
   134 
   135 
   136 + (NSData*) encodeData: (NSData*)data
   137                 signer: (MYIdentity*)signer
   138              recipient: (MYCertificate*)recipient
   139                  error: (NSError**)outError
   140 {
   141     MYEncoder *e = [[self alloc] init];
   142     if( signer )
   143         [e addSigner: signer];
   144     if( recipient )
   145         [e addRecipient: recipient];
   146     [e addData: data];
   147     *outError = e.error;
   148     NSData *result = e.encodedData;
   149     [e release];
   150     return result;
   151 }
   152 
   153 
   154 @end
   155 
   156 
   157 #if DEBUG
   158 
   159 #import "MYCrypto+Cocoa.h"
   160 
   161 TestCase(MYEncoder) {
   162     MYIdentity *me = nil;//[MYIdentity preferredIdentityForName: @"MYCryptoTest"];
   163     if (!me) {
   164         NSArray *idents = [[[MYKeychain allKeychains] enumerateIdentities] allObjects];
   165         SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];
   166         [panel setAlternateButtonTitle: @"Cancel"];
   167         if ([panel my_runModalForIdentities: idents 
   168                                     message: @"Choose an identity for the MYEncoder test case:"]
   169                 != NSOKButton) {
   170             [NSException raise: NSGenericException format: @"User canceled"];
   171         }
   172         me = [panel my_identity];
   173         [me makePreferredIdentityForName: @"MYCryptoTest"];
   174     }
   175     CAssert(me,@"No default identity has been set up in the Keychain");
   176     
   177     NSData *source = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
   178     CAssert(source);
   179     
   180     NSError *error;
   181     NSData *encoded;
   182     
   183     Log(@"Testing signing...");
   184     encoded = [MYEncoder encodeData: source signer: me recipient: nil error: &error];
   185     CAssertEq(error,nil);
   186     CAssert([encoded length]);
   187     Log(@"MYEncoder signed %u bytes into %u bytes", source.length,encoded.length);
   188     
   189     Log(@"Testing encryption...");
   190     encoded = [MYEncoder encodeData: source signer: nil recipient: me error: &error];
   191     CAssertEq(error,nil);
   192     CAssert([encoded length]);
   193     Log(@"MYEncoder encrypted %u bytes into %u bytes", source.length,encoded.length);
   194     
   195     Log(@"Testing signing+encryption...");
   196     encoded = [MYEncoder encodeData: source signer: me recipient: me error: &error];
   197     CAssertEq(error,nil);
   198     CAssert([encoded length]);
   199     Log(@"MYEncoder signed/encrypted %u bytes into %u bytes", source.length,encoded.length);
   200 }
   201 #endif
   202 
   203 
   204 
   205 /*
   206  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   207  
   208  Redistribution and use in source and binary forms, with or without modification, are permitted
   209  provided that the following conditions are met:
   210  
   211  * Redistributions of source code must retain the above copyright notice, this list of conditions
   212  and the following disclaimer.
   213  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   214  and the following disclaimer in the documentation and/or other materials provided with the
   215  distribution.
   216  
   217  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   218  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   219  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   220  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   221  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   222   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   223  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   224  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   225  */