snej@8
|
1 |
//
|
snej@8
|
2 |
// CryptoDecoder.h
|
snej@8
|
3 |
// Cloudy
|
snej@8
|
4 |
//
|
snej@8
|
5 |
// Created by Jens Alfke on 1/16/08.
|
snej@8
|
6 |
// Copyright 2008 Jens Alfke. All rights reserved.
|
snej@8
|
7 |
//
|
snej@8
|
8 |
|
snej@8
|
9 |
#import <Cocoa/Cocoa.h>
|
snej@8
|
10 |
#import <Security/CMSDecoder.h>
|
snej@8
|
11 |
|
snej@8
|
12 |
@class MYKeychain, MYCertificate;
|
snej@8
|
13 |
|
snej@8
|
14 |
|
snej@8
|
15 |
/** Decodes a CMS-formatted message into the original data, and identifies & verifies signatures. */
|
snej@8
|
16 |
@interface MYDecoder : NSObject
|
snej@8
|
17 |
{
|
snej@8
|
18 |
@private
|
snej@8
|
19 |
CMSDecoderRef _decoder;
|
snej@8
|
20 |
OSStatus _error;
|
snej@8
|
21 |
SecPolicyRef _policy;
|
snej@8
|
22 |
}
|
snej@8
|
23 |
|
snej@8
|
24 |
/** Initializes a new decoder. */
|
snej@8
|
25 |
- (id) init;
|
snej@8
|
26 |
|
snej@8
|
27 |
/** Initializes a new decoder and reads the entire message data. */
|
snej@8
|
28 |
- (id) initWithData: (NSData*)data error: (NSError**)outError;
|
snej@8
|
29 |
|
snej@8
|
30 |
/** Specifies a keychain to use to look up certificates and keys, instead of the default
|
snej@8
|
31 |
keychain search path. */
|
snej@8
|
32 |
- (BOOL) useKeychain: (MYKeychain*)keychain;
|
snej@8
|
33 |
|
snej@8
|
34 |
/** Adds data to the decoder. You can add the entire data at once, or in bits and pieces
|
snej@8
|
35 |
(if you're reading it from a stream). */
|
snej@8
|
36 |
- (BOOL) addData: (NSData*)data;
|
snej@8
|
37 |
|
snej@8
|
38 |
/** The error, if any, that occurred while decoding the content.
|
snej@8
|
39 |
If -addData: returns NO, read this property to find out what went wrong.
|
snej@8
|
40 |
The most likely error is (NSOSStatusErrorDomain, errSecUnknownFormat). */
|
snej@8
|
41 |
@property (readonly) NSError *error;
|
snej@8
|
42 |
|
snej@8
|
43 |
/** If the message content is detached (stored separately from the encoded message),
|
snej@8
|
44 |
you must copy it to this property before calling -finish, so that the decoder can use it
|
snej@8
|
45 |
to verify signatures. */
|
snej@8
|
46 |
@property (retain) NSData *detachedContent;
|
snej@8
|
47 |
|
snej@8
|
48 |
/** Tells the decoder that all of the data has been read, after the last call to -addData:.
|
snej@8
|
49 |
You must call this before accessing the message content or metadata. */
|
snej@8
|
50 |
- (BOOL) finish;
|
snej@8
|
51 |
|
snej@8
|
52 |
/** The decoded message content. */
|
snej@8
|
53 |
@property (readonly) NSData* content;
|
snej@8
|
54 |
|
snej@8
|
55 |
/** YES if the message was signed. (Use the signers property to see who signed it.) */
|
snej@8
|
56 |
@property (readonly) BOOL isSigned;
|
snej@8
|
57 |
|
snej@8
|
58 |
/** YES if the message was encrypted. */
|
snej@8
|
59 |
@property (readonly) BOOL isEncrypted;
|
snej@8
|
60 |
|
snej@8
|
61 |
/** An array of MYSigner objects representing the identities who signed the message.
|
snej@8
|
62 |
Nil if the message is unsigned. */
|
snej@8
|
63 |
@property (readonly) NSArray* signers;
|
snej@8
|
64 |
|
snej@8
|
65 |
/** All of the certificates (as MYCertificate objects) that were attached to the message. */
|
snej@8
|
66 |
@property (readonly) NSArray* certificates;
|
snej@8
|
67 |
|
snej@8
|
68 |
|
snej@8
|
69 |
/** @name Expert
|
snej@8
|
70 |
* Advanced methods.
|
snej@8
|
71 |
*/
|
snej@8
|
72 |
//@{
|
snej@8
|
73 |
|
snej@8
|
74 |
/** The X.509 content-type of the message contents.
|
snej@8
|
75 |
The Data field points to autoreleased memory: do not free it yourself, and do not
|
snej@8
|
76 |
expect it to remain valid after the calling method returns. */
|
snej@8
|
77 |
@property (readonly) CSSM_OID contentType;
|
snej@8
|
78 |
|
snej@8
|
79 |
/** The Policy that will be used to evaluate trust when calling MYSigner.copyTrust.
|
snej@8
|
80 |
NULL by default. */
|
snej@8
|
81 |
@property (assign) SecPolicyRef policy;
|
snej@8
|
82 |
|
snej@8
|
83 |
/** Returns a string with detailed information about the message metadata.
|
snej@8
|
84 |
Not user-presentable; used for debugging. */
|
snej@8
|
85 |
- (NSString*) dump;
|
snej@8
|
86 |
|
snej@8
|
87 |
//@}
|
snej@8
|
88 |
|
snej@8
|
89 |
@end
|
snej@8
|
90 |
|
snej@8
|
91 |
|
snej@8
|
92 |
/** Represents a signer of a CMS message, as returned by the MYDecoder.signers property. */
|
snej@8
|
93 |
@interface MYSigner : NSObject
|
snej@8
|
94 |
{
|
snej@8
|
95 |
@private
|
snej@8
|
96 |
CMSDecoderRef _decoder;
|
snej@8
|
97 |
size_t _index;
|
snej@8
|
98 |
CFTypeRef _policy;
|
snej@8
|
99 |
CMSSignerStatus _status;
|
snej@8
|
100 |
OSStatus _verifyResult;
|
snej@8
|
101 |
SecTrustRef _trust;
|
snej@8
|
102 |
}
|
snej@8
|
103 |
|
snej@8
|
104 |
/** The status of the signature, i.e. whether it's valid or not.
|
snej@8
|
105 |
* Values include:
|
snej@8
|
106 |
* kCMSSignerValid :both signature and signer certificate verified OK.
|
snej@8
|
107 |
* kCMSSignerNeedsDetachedContent:the MYDecoder's detachedContent property must be set,
|
snej@8
|
108 |
* to ascertain the signature status.
|
snej@8
|
109 |
* kCMSSignerInvalidSignature :bad signature -- either the content or the signature
|
snej@8
|
110 |
* data were tampered with after the message was encoded.
|
snej@8
|
111 |
* kCMSSignerInvalidCert :an error occurred verifying the signer's certificate.
|
snej@8
|
112 |
* Further information available via the verifyResult
|
snej@8
|
113 |
* and copyTrust methods.
|
snej@8
|
114 |
*/
|
snej@8
|
115 |
@property (readonly) CMSSignerStatus status;
|
snej@8
|
116 |
|
snej@8
|
117 |
/** The signer's certificate.
|
snej@8
|
118 |
You should check the status property first, to see whether the signature and certificate
|
snej@8
|
119 |
are valid.
|
snej@8
|
120 |
For safety purposes, if you haven't checked status yet, this method will return nil
|
snej@8
|
121 |
if the signer status is not kCMSSignerValid. */
|
snej@8
|
122 |
@property (readonly) MYCertificate *certificate;
|
snej@8
|
123 |
|
snej@8
|
124 |
/** The signer's email address (if any), as stored in the certificate. */
|
snej@8
|
125 |
@property (readonly) NSString* emailAddress;
|
snej@8
|
126 |
|
snej@8
|
127 |
/** @name Expert
|
snej@8
|
128 |
* Advanced methods.
|
snej@8
|
129 |
*/
|
snej@8
|
130 |
//@{
|
snej@8
|
131 |
|
snej@8
|
132 |
/** Returns the SecTrustRef that was used to verify the certificate.
|
snej@8
|
133 |
You can use this object to get more detailed information about how the verification was done.
|
snej@8
|
134 |
If you set the parent decoder's policy property, then that SecPolicy will be used to evaluate
|
snej@9
|
135 |
trust; otherwise you'll need to do it yourself using the SecTrust object. */
|
snej@9
|
136 |
@property (readonly) SecTrustRef trust;
|
snej@8
|
137 |
|
snej@8
|
138 |
/** The result of certificate verification, as a CSSM_RESULT code;
|
snej@8
|
139 |
* a nonzero value indicates an error.
|
snej@8
|
140 |
*
|
snej@8
|
141 |
* Some of the most common and interesting errors are:
|
snej@8
|
142 |
*
|
snej@8
|
143 |
* CSSMERR_TP_INVALID_ANCHOR_CERT : The cert was verified back to a
|
snej@8
|
144 |
* self-signed (root) cert which was present in the message, but
|
snej@8
|
145 |
* that root cert is not a known, trusted root cert.
|
snej@8
|
146 |
* CSSMERR_TP_NOT_TRUSTED: The cert could not be verified back to
|
snej@8
|
147 |
* a root cert.
|
snej@8
|
148 |
* CSSMERR_TP_VERIFICATION_FAILURE: A root cert was found which does
|
snej@8
|
149 |
* not self-verify.
|
snej@8
|
150 |
* CSSMERR_TP_VERIFY_ACTION_FAILED: Indicates a failure of the requested
|
snej@8
|
151 |
* policy action.
|
snej@8
|
152 |
* CSSMERR_TP_INVALID_CERTIFICATE: Indicates a bad leaf cert.
|
snej@8
|
153 |
* CSSMERR_TP_CERT_EXPIRED: A cert in the chain was expired at the time of
|
snej@8
|
154 |
* verification.
|
snej@8
|
155 |
* CSSMERR_TP_CERT_NOT_VALID_YET: A cert in the chain was not yet valie at
|
snej@8
|
156 |
* the time of verification.
|
snej@8
|
157 |
*/
|
snej@8
|
158 |
@property (readonly) OSStatus verifyResult;
|
snej@8
|
159 |
|
snej@8
|
160 |
//@}
|
snej@8
|
161 |
|
snej@8
|
162 |
@end
|
snej@8
|
163 |
|
snej@8
|
164 |
|
snej@8
|
165 |
enum {
|
snej@8
|
166 |
/** Returned from MYSigner.status to indicate a failure (non-noErr return value)
|
snej@8
|
167 |
of the underlying CMSDecoderCopySignerStatus call. Should never occur. */
|
snej@8
|
168 |
kMYSignerStatusCheckFailed = 666
|
snej@8
|
169 |
};
|