I'm creating a linked list and using containers to group the object, next, and previous properties. Like Foundation collections, I'd like it to implement NSSecureCoding
. Here's the declaration:
@interface ListContainer : NSObject <NSCopying, NSSecureCoding>
@property (readonly, nonatomic) id object;
@property (nonatomic) ListContainer * next;
@property (nonatomic) ListContainer * previous;
@end
When implementing the - initWithCoder:
method it hit me that I don't know what class to use for the object:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
_object = [aDecoder decodeObjectOfClass:<#(__unsafe_unretained Class)#> forKey:@"object"];
BOOL nextIsNil = [aDecoder decodeBoolForKey:@"nextIsNil"];
if (!nextIsNil) {
// Decode next
_next = [aDecoder decodeObjectOfClass:[ListContainer class] forKey:@"next"];
if (_next == nil) {
return nil;
}
// Link the nodes manually to prevent infinite recursion
self.next.previous = self;
}
}
return self;
}
Should I use -decodeObjectForKey:
instead? Is it still secure coding?
I ended up posting the same question to Cocoa's mailing list and the most interesting discussion happened. Some of the highlights:
At this point I understand that NSArray doesn't behave as I expected. Secure coding doesn't seem so secure anymore:
Getting a class that I'm not expecting in a substitution attack is especially dreadful. Apparently Cocoa's promise is different, though:
So, no,
NSSecureCoding
does not guarantee secure encoding of containers, or at least it doesn't guarantee type checking and you must do it yourself. Not even in Cocoa's native data structures as I initially assumed (with reason, I still think that).Props go to Roland King for all the effort. You can see the full conversation here.