1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/MYEncoder.m Sat Apr 18 18:12:06 2009 -0700
1.3 @@ -0,0 +1,201 @@
1.4 +//
1.5 +// MYEncoder.m
1.6 +// MYCrypto
1.7 +//
1.8 +// Created by Jens Alfke on 1/16/08.
1.9 +// Copyright 2008-2009 Jens Alfke. All rights reserved.
1.10 +//
1.11 +
1.12 +#import "MYEncoder.h"
1.13 +#import "MYIdentity.h"
1.14 +#import "MYCrypto_Private.h"
1.15 +#import "Test.h"
1.16 +#import "MYErrorUtils.h"
1.17 +
1.18 +
1.19 +@implementation MYEncoder
1.20 +
1.21 +
1.22 +- (id) init
1.23 +{
1.24 + self = [super init];
1.25 + if (self != nil) {
1.26 + if( ! checksave(CMSEncoderCreate(&_encoder)) ) {
1.27 + [self release];
1.28 + return nil;
1.29 + }
1.30 + }
1.31 + return self;
1.32 +}
1.33 +
1.34 +- (void) dealloc
1.35 +{
1.36 + if(_encoder) CFRelease(_encoder);
1.37 + [super dealloc];
1.38 +}
1.39 +
1.40 +
1.41 +
1.42 +- (BOOL) addSigner: (MYIdentity*)signer
1.43 +{
1.44 + Assert(signer);
1.45 + return checksave( CMSEncoderAddSigners(_encoder, signer.identityRef) );
1.46 +}
1.47 +
1.48 +- (BOOL) addRecipient: (MYCertificate*)recipient
1.49 +{
1.50 + Assert(recipient);
1.51 + return checksave( CMSEncoderAddRecipients(_encoder, recipient.certificateRef) );
1.52 +}
1.53 +
1.54 +- (BOOL) addSupportingCert: (MYCertificate*)supportingCert
1.55 +{
1.56 + Assert(supportingCert);
1.57 + return checksave( CMSEncoderAddSupportingCerts(_encoder, supportingCert.certificateRef) );
1.58 +}
1.59 +
1.60 +- (BOOL) addTimestamp
1.61 +{
1.62 + return checksave( CMSEncoderAddSignedAttributes(_encoder, kCMSAttrSigningTime) );
1.63 +}
1.64 +
1.65 +
1.66 +- (NSError*) error
1.67 +{
1.68 + if( _error )
1.69 + return MYError(_error, NSOSStatusErrorDomain,
1.70 + @"%@", MYErrorName(NSOSStatusErrorDomain,_error));
1.71 + else
1.72 + return nil;
1.73 +}
1.74 +
1.75 +
1.76 +- (CMSCertificateChainMode) certificateChainMode
1.77 +{
1.78 + CMSCertificateChainMode mode;
1.79 + if( CMSEncoderGetCertificateChainMode(_encoder, &mode) == noErr )
1.80 + return mode;
1.81 + else
1.82 + return -1;
1.83 +}
1.84 +
1.85 +- (void) setCertificateChainMode: (CMSCertificateChainMode)mode
1.86 +{
1.87 + checksave( CMSEncoderSetCertificateChainMode(_encoder, mode) );
1.88 +}
1.89 +
1.90 +- (BOOL) hasDetachedContent
1.91 +{
1.92 + Boolean detached;
1.93 + return CMSEncoderGetHasDetachedContent(_encoder, &detached)==noErr && detached;
1.94 +}
1.95 +
1.96 +- (void) setHasDetachedContent: (BOOL)detached
1.97 +{
1.98 + checksave( CMSEncoderSetHasDetachedContent(_encoder, detached) );
1.99 +}
1.100 +
1.101 +- (NSData*) _dataFromFunction: (OSStatus (*)(CMSEncoderRef,CFDataRef*))function
1.102 +{
1.103 + CFDataRef data=NULL;
1.104 + if( checksave( (*function)(_encoder, &data) ) )
1.105 + return [(NSData*)CFMakeCollectable(data) autorelease];
1.106 + else
1.107 + return nil;
1.108 +}
1.109 +
1.110 +
1.111 +- (CSSM_OID) contentType
1.112 +{
1.113 + NSData *data = [self _dataFromFunction: &CMSEncoderCopyEncapsulatedContentType];
1.114 + return (CSSM_OID){data.length,(uint8*)data.bytes};
1.115 +}
1.116 +
1.117 +- (void) setContentType: (CSSM_OID)contentType
1.118 +{
1.119 + checksave( CMSEncoderSetEncapsulatedContentType(_encoder, &contentType) );
1.120 +}
1.121 +
1.122 +
1.123 +- (BOOL) addData: (NSData*)data
1.124 +{
1.125 + Assert(data);
1.126 + return ! _error && checksave( CMSEncoderUpdateContent(_encoder, data.bytes, data.length) );
1.127 +}
1.128 +
1.129 +
1.130 +- (NSData*) encodedData
1.131 +{
1.132 + if( ! _error )
1.133 + return [self _dataFromFunction: &CMSEncoderCopyEncodedContent];
1.134 + else
1.135 + return nil;
1.136 +}
1.137 +
1.138 +
1.139 ++ (NSData*) encodeData: (NSData*)data
1.140 + signer: (MYIdentity*)signer
1.141 + recipient: (MYCertificate*)recipient
1.142 + error: (NSError**)outError
1.143 +{
1.144 + MYEncoder *e = [[self alloc] init];
1.145 + if( signer )
1.146 + [e addSigner: signer];
1.147 + if( recipient )
1.148 + [e addRecipient: recipient];
1.149 + [e addData: data];
1.150 + *outError = e.error;
1.151 + NSData *result = e.encodedData;
1.152 + [e release];
1.153 + return result;
1.154 +}
1.155 +
1.156 +
1.157 +@end
1.158 +
1.159 +
1.160 +#if DEBUG
1.161 +
1.162 +#import "MYCrypto+Cocoa.h"
1.163 +
1.164 +TestCase(MYEncoder) {
1.165 + MYIdentity *me = nil;//[MYIdentity preferredIdentityForName: @"MYCryptoTest"];
1.166 + if (!me) {
1.167 + NSArray *idents = [[[MYKeychain allKeychains] enumerateIdentities] allObjects];
1.168 + SFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];
1.169 + [panel setAlternateButtonTitle: @"Cancel"];
1.170 + if ([panel my_runModalForIdentities: idents
1.171 + message: @"Choose an identity for the MYEncoder test case:"]
1.172 + != NSOKButton) {
1.173 + [NSException raise: NSGenericException format: @"User canceled"];
1.174 + }
1.175 + me = [panel my_identity];
1.176 + [me makePreferredIdentityForName: @"MYCryptoTest"];
1.177 + }
1.178 + CAssert(me,@"No default identity has been set up in the Keychain");
1.179 +
1.180 + NSData *source = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
1.181 + CAssert(source);
1.182 +
1.183 + NSError *error;
1.184 + NSData *encoded;
1.185 +
1.186 + Log(@"Testing signing...");
1.187 + encoded = [MYEncoder encodeData: source signer: me recipient: nil error: &error];
1.188 + CAssertEq(error,nil);
1.189 + CAssert([encoded length]);
1.190 + Log(@"MYEncoder signed %u bytes into %u bytes", source.length,encoded.length);
1.191 +
1.192 + Log(@"Testing encryption...");
1.193 + encoded = [MYEncoder encodeData: source signer: nil recipient: me error: &error];
1.194 + CAssertEq(error,nil);
1.195 + CAssert([encoded length]);
1.196 + Log(@"MYEncoder encrypted %u bytes into %u bytes", source.length,encoded.length);
1.197 +
1.198 + Log(@"Testing signing+encryption...");
1.199 + encoded = [MYEncoder encodeData: source signer: me recipient: me error: &error];
1.200 + CAssertEq(error,nil);
1.201 + CAssert([encoded length]);
1.202 + Log(@"MYEncoder signed/encrypted %u bytes into %u bytes", source.length,encoded.length);
1.203 +}
1.204 +#endif