blob: 527e40dc80ef5137c03deef1bc6643fe2674e4e5 [file]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/web/public/crw_session_certificate_policy_cache_storage.h"
#import "base/strings/sys_string_conversions.h"
#include "net/base/hash_value.h"
#include "net/cert/x509_certificate.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// CRWSessionCertificateStorage serialization keys.
NSString* const kCertificateSerializationKey = @"CertificateSerializationKey";
NSString* const kHostSerializationKey = @"HostSerializationKey";
NSString* const kStatusSerializationKey = @"StatusSerializationKey";
// CRWSessionCertificatePolicyCacheStorage serialization keys.
NSString* const kCertificateStoragesKey = @"kCertificateStoragesKey";
NSString* const kCertificateStoragesDeprecatedKey = @"allowedCertificates";
// The deprecated serialization technique serialized each certificate policy as
// an NSArray, where the necessary information is stored at the following
// indices.
typedef NS_ENUM(NSInteger, DeprecatedSerializationIndices) {
CertificateDataIndex = 0,
HostStringIndex,
StatusIndex,
DeprecatedSerializationIndexCount,
};
// Converts |certificate| to NSData for serialization.
NSData* CertificateToNSData(net::X509Certificate* certificate) {
std::string cert_string;
bool success = net::X509Certificate::GetDEREncoded(
certificate->os_cert_handle(), &cert_string);
DCHECK(success);
return [NSData dataWithBytes:cert_string.c_str() length:cert_string.length()];
}
// Converts serialized NSData to a certificate.
scoped_refptr<net::X509Certificate> NSDataToCertificate(NSData* data) {
return net::X509Certificate::CreateFromBytes(
static_cast<const char*>(data.bytes), data.length);
}
} // namespace
#pragma mark - CRWSessionCertificateStorage
@interface CRWSessionCertificateStorage () {
// Backing objects for properties of the same name.
scoped_refptr<net::X509Certificate> _certificate;
std::string _host;
}
// Initializes the CRWSessionCertificateStorage using the deprecated
// serialization technique. See DeprecatedSerializationIndices above for more
// details.
- (instancetype)initWithDeprecatedSerialization:(NSArray*)serialization;
@end
@implementation CRWSessionCertificateStorage
@synthesize host = _host;
@synthesize status = _status;
- (instancetype)initWithCertificate:(scoped_refptr<net::X509Certificate>)cert
host:(const std::string&)host
status:(net::CertStatus)status {
if ((self = [super init])) {
_certificate = cert;
_host = host;
_status = status;
}
return self;
}
#pragma mark Accessors
- (net::X509Certificate*)certificate {
return _certificate.get();
}
#pragma mark NSCoding
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
NSData* certData = [aDecoder decodeObjectForKey:kCertificateSerializationKey];
NSString* hostString = [aDecoder decodeObjectForKey:kHostSerializationKey];
NSNumber* statusNumber =
[aDecoder decodeObjectForKey:kStatusSerializationKey];
if (!certData.length || !hostString.length || !statusNumber)
return nil;
return [self initWithCertificate:NSDataToCertificate(certData)
host:base::SysNSStringToUTF8(hostString)
status:statusNumber.unsignedIntegerValue];
}
- (void)encodeWithCoder:(NSCoder*)aCoder {
[aCoder encodeObject:CertificateToNSData(_certificate.get())
forKey:kCertificateSerializationKey];
[aCoder encodeObject:base::SysUTF8ToNSString(_host)
forKey:kHostSerializationKey];
[aCoder encodeObject:@(_status) forKey:kStatusSerializationKey];
}
#pragma mark Private
- (instancetype)initWithDeprecatedSerialization:(NSArray*)serialization {
if (serialization.count != DeprecatedSerializationIndexCount)
return nil;
NSData* certData = serialization[CertificateDataIndex];
NSString* hostString = serialization[HostStringIndex];
NSNumber* statusNumber = serialization[StatusIndex];
if (!certData.length || !hostString.length || !statusNumber)
return nil;
return [self initWithCertificate:NSDataToCertificate(certData)
host:base::SysNSStringToUTF8(hostString)
status:[statusNumber unsignedIntegerValue]];
}
@end
#pragma mark - CRWSessionCertificatePolicyCacheStorage
@implementation CRWSessionCertificatePolicyCacheStorage
@synthesize certificateStorages = _certificateStorages;
#pragma mark NSCoding
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
if ((self = [super init])) {
_certificateStorages =
[aDecoder decodeObjectForKey:kCertificateStoragesKey];
if (!_certificateStorages.count) {
// Attempt to use the deprecated serialization if none were decoded.
NSMutableSet* deprecatedSerializations =
[aDecoder decodeObjectForKey:kCertificateStoragesDeprecatedKey];
NSMutableSet* certificateStorages = [[NSMutableSet alloc]
initWithCapacity:deprecatedSerializations.count];
for (NSArray* serialiazation in deprecatedSerializations) {
CRWSessionCertificateStorage* certificatePolicyStorage =
[[CRWSessionCertificateStorage alloc]
initWithDeprecatedSerialization:serialiazation];
if (certificatePolicyStorage)
[certificateStorages addObject:certificatePolicyStorage];
}
_certificateStorages = certificateStorages;
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder*)aCoder {
[aCoder encodeObject:self.certificateStorages forKey:kCertificateStoragesKey];
}
@end