5 // Created by Jens Alfke on 1/16/08.
6 // Copyright 2008-2009 Jens Alfke. All rights reserved.
10 #import "MYIdentity.h"
11 #import "MYCrypto_Private.h"
13 #import "MYErrorUtils.h"
16 @implementation MYEncoder
23 if( ! checksave(CMSEncoderCreate(&_encoder)) ) {
33 if(_encoder) CFRelease(_encoder);
39 - (BOOL) addSigner: (MYIdentity*)signer
42 return checksave( CMSEncoderAddSigners(_encoder, signer.identityRef) );
45 - (BOOL) addRecipient: (MYCertificate*)recipient
48 return checksave( CMSEncoderAddRecipients(_encoder, recipient.certificateRef) );
51 - (BOOL) addSupportingCert: (MYCertificate*)supportingCert
53 Assert(supportingCert);
54 return checksave( CMSEncoderAddSupportingCerts(_encoder, supportingCert.certificateRef) );
59 return checksave( CMSEncoderAddSignedAttributes(_encoder, kCMSAttrSigningTime) );
66 return MYError(_error, NSOSStatusErrorDomain,
67 @"%@", MYErrorName(NSOSStatusErrorDomain,_error));
73 - (CMSCertificateChainMode) certificateChainMode
75 CMSCertificateChainMode mode;
76 if( CMSEncoderGetCertificateChainMode(_encoder, &mode) == noErr )
82 - (void) setCertificateChainMode: (CMSCertificateChainMode)mode
84 checksave( CMSEncoderSetCertificateChainMode(_encoder, mode) );
87 - (BOOL) hasDetachedContent
90 return CMSEncoderGetHasDetachedContent(_encoder, &detached)==noErr && detached;
93 - (void) setHasDetachedContent: (BOOL)detached
95 checksave( CMSEncoderSetHasDetachedContent(_encoder, detached) );
98 - (NSData*) _dataFromFunction: (OSStatus (*)(CMSEncoderRef,CFDataRef*))function
101 if( checksave( (*function)(_encoder, &data) ) )
102 return [(NSData*)CFMakeCollectable(data) autorelease];
108 - (CSSM_OID) contentType
110 NSData *data = [self _dataFromFunction: &CMSEncoderCopyEncapsulatedContentType];
111 return (CSSM_OID){data.length,(uint8*)data.bytes};
114 - (void) setContentType: (CSSM_OID)contentType
116 checksave( CMSEncoderSetEncapsulatedContentType(_encoder, &contentType) );
120 - (BOOL) addData: (NSData*)data
123 return ! _error && checksave( CMSEncoderUpdateContent(_encoder, data.bytes, data.length) );
127 - (NSData*) encodedData
130 return [self _dataFromFunction: &CMSEncoderCopyEncodedContent];
136 + (NSData*) encodeData: (NSData*)data
137 signer: (MYIdentity*)signer
138 recipient: (MYCertificate*)recipient
139 error: (NSError**)outError
141 MYEncoder *e = [[self alloc] init];
143 [e addSigner: signer];
145 [e addRecipient: recipient];
148 NSData *result = e.encodedData;
159 #import "MYCrypto+Cocoa.h"
161 TestCase(MYEncoder) {
162 MYIdentity *me = nil;//[MYIdentity preferredIdentityForName: @"MYCryptoTest"];
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:"]
170 [NSException raise: NSGenericException format: @"User canceled"];
172 me = [panel my_identity];
173 [me makePreferredIdentityForName: @"MYCryptoTest"];
175 CAssert(me,@"No default identity has been set up in the Keychain");
177 NSData *source = [NSData dataWithContentsOfFile: @"/Library/Desktop Pictures/Nature/Zen Garden.jpg"];
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);
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);
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);