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