Add methods for easier certificate verification
This commit is contained in:
parent
53932c0acb
commit
3b0fbe7868
2 changed files with 109 additions and 1 deletions
|
@ -55,7 +55,13 @@
|
||||||
- (OFDictionary*)issuer;
|
- (OFDictionary*)issuer;
|
||||||
- (OFDictionary*)subject;
|
- (OFDictionary*)subject;
|
||||||
- (OFDictionary*)subjectAlternativeName;
|
- (OFDictionary*)subjectAlternativeName;
|
||||||
|
- (BOOL)hasCommonNameMatchingDomain: (OFString*)domain;
|
||||||
|
- (BOOL)hasDNSNameMatchingDomain: (OFString*)domain;
|
||||||
|
- (BOOL)hasSRVNameMatchingDomain: (OFString*)domain
|
||||||
|
service: (OFString*)service;
|
||||||
|
- (BOOL)X509_isAssertedDomain: (OFString*)asserted
|
||||||
|
equalDomain: (OFString*)domain;
|
||||||
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name;
|
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name;
|
||||||
- (OFString*)X509_stringFromASN1Object: (ASN1_OBJECT*)obj;
|
- (OFString*)X509_stringFromASN1Object: (ASN1_OBJECT*)obj;
|
||||||
- (OFString*) X509_stringFromASN1String: (ASN1_STRING*)str;
|
- (OFString*)X509_stringFromASN1String: (ASN1_STRING*)str;
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -241,6 +241,108 @@
|
||||||
return (subjectAlternativeName = ret);
|
return (subjectAlternativeName = ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasCommonNameMatchingDomain: (OFString*)domain
|
||||||
|
{
|
||||||
|
OFString *name;
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
OFList *CNs = [[self subject] objectForKey: OID_commonName];
|
||||||
|
|
||||||
|
for (name in CNs) {
|
||||||
|
if ([self X509_isAssertedDomain: name
|
||||||
|
equalDomain: domain]) {
|
||||||
|
[pool release];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasDNSNameMatchingDomain: (OFString*)domain
|
||||||
|
{
|
||||||
|
OFString *name;
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
OFDictionary *SANs = [self subjectAlternativeName];
|
||||||
|
OFList *assertedNames = [SANs objectForKey: @"dNSName"];
|
||||||
|
|
||||||
|
for (name in assertedNames) {
|
||||||
|
if ([self X509_isAssertedDomain: name
|
||||||
|
equalDomain: domain]) {
|
||||||
|
[pool release];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)hasSRVNameMatchingDomain: (OFString*)domain
|
||||||
|
service: (OFString*)service
|
||||||
|
{
|
||||||
|
size_t serviceLength;
|
||||||
|
OFString *name;
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
OFDictionary *SANs = [self subjectAlternativeName];
|
||||||
|
OFList *assertedNames = [[SANs objectForKey: @"otherName"]
|
||||||
|
objectForKey: OID_SRVName];
|
||||||
|
|
||||||
|
if (![service hasPrefix: @"_"])
|
||||||
|
service = [service stringByPrependingString: @"_"];
|
||||||
|
|
||||||
|
service = [service stringByAppendingString: @"."];
|
||||||
|
serviceLength = [service length];
|
||||||
|
|
||||||
|
for (name in assertedNames) {
|
||||||
|
if ([name hasPrefix: service]) {
|
||||||
|
OFString *asserted;
|
||||||
|
asserted = [name substringWithRange:
|
||||||
|
of_range(serviceLength,
|
||||||
|
[name length] - serviceLength)];
|
||||||
|
if ([self X509_isAssertedDomain: asserted
|
||||||
|
equalDomain: domain]) {
|
||||||
|
[pool release];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) X509_isAssertedDomain: (OFString*)asserted
|
||||||
|
equalDomain: (OFString*)domain
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In accordance with RFC 6125 this only allows a wildcard as the
|
||||||
|
* left-most label and matches only the left-most label with it.
|
||||||
|
* E.g. *.example.com matches foo.example.com,
|
||||||
|
* but not foo.bar.example.com
|
||||||
|
*/
|
||||||
|
size_t firstDot;
|
||||||
|
if (![asserted caseInsensitiveCompare: domain])
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
if (![asserted hasPrefix: @"*."])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
asserted = [asserted substringWithRange: of_range(2,
|
||||||
|
[asserted length] - 2)];
|
||||||
|
|
||||||
|
firstDot = [domain indexOfFirstOccurrenceOfString: @"."];
|
||||||
|
if (firstDot == OF_INVALID_INDEX)
|
||||||
|
return NO;
|
||||||
|
domain = [domain substringWithRange: of_range(firstDot + 1,
|
||||||
|
[domain length] - firstDot - 1)];
|
||||||
|
|
||||||
|
if (![asserted caseInsensitiveCompare: domain])
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name
|
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
Reference in a new issue