Cleanup and fix X509Certificate.
This commit is contained in:
parent
165ee6acca
commit
22ce8a2a8c
1 changed files with 90 additions and 78 deletions
|
@ -92,7 +92,7 @@
|
||||||
|
|
||||||
- (OFString*)description
|
- (OFString*)description
|
||||||
{
|
{
|
||||||
OFMutableString *ret = nil;//[OFMutableString string];
|
OFMutableString *ret = [OFMutableString string];
|
||||||
|
|
||||||
[ret appendFormat: @"Issuer: %@\n\n", [self issuer]];
|
[ret appendFormat: @"Issuer: %@\n\n", [self issuer]];
|
||||||
[ret appendFormat: @"Subject: %@\n\n", [self subject]];
|
[ret appendFormat: @"Subject: %@\n\n", [self subject]];
|
||||||
|
@ -104,63 +104,71 @@
|
||||||
|
|
||||||
- (OFDictionary*)issuer
|
- (OFDictionary*)issuer
|
||||||
{
|
{
|
||||||
if (issuer == nil) {
|
X509_NAME *name;
|
||||||
X509_NAME *name = X509_get_issuer_name(crt);
|
|
||||||
issuer = [[self X509_dictionaryFromX509Name: name] retain];
|
if (issuer != nil)
|
||||||
}
|
return [[issuer copy] autorelease];
|
||||||
|
|
||||||
|
name = X509_get_issuer_name(crt);
|
||||||
|
issuer = [[self X509_dictionaryFromX509Name: name] retain];
|
||||||
|
|
||||||
return issuer;
|
return issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDictionary*)subject
|
- (OFDictionary*)subject
|
||||||
{
|
{
|
||||||
if (subject == nil) {
|
X509_NAME *name;
|
||||||
X509_NAME *name = X509_get_subject_name(crt);
|
|
||||||
subject = [[self X509_dictionaryFromX509Name: name] retain];
|
if (subject != nil)
|
||||||
}
|
return [[subject copy] autorelease];
|
||||||
|
|
||||||
|
name = X509_get_subject_name(crt);
|
||||||
|
subject = [[self X509_dictionaryFromX509Name: name] retain];
|
||||||
|
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFDictionary*)subjectAlternativeName
|
- (OFDictionary*)subjectAlternativeName
|
||||||
{
|
{
|
||||||
|
OFAutoreleasePool *pool;
|
||||||
|
OFMutableDictionary *ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (subjectAlternativeName != nil)
|
if (subjectAlternativeName != nil)
|
||||||
return subjectAlternativeName;
|
return [[subjectAlternativeName copy] autorelease];
|
||||||
|
|
||||||
int i = -1, j;
|
ret = [OFMutableDictionary dictionary];
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
pool = [[OFAutoreleasePool alloc] init];
|
||||||
OFMutableDictionary *ret = [OFMutableDictionary dictionary];
|
|
||||||
|
|
||||||
|
i = -1;
|
||||||
while ((i = X509_get_ext_by_NID(crt, NID_subject_alt_name, i)) != -1) {
|
while ((i = X509_get_ext_by_NID(crt, NID_subject_alt_name, i)) != -1) {
|
||||||
X509_EXTENSION *extension;
|
X509_EXTENSION *extension;
|
||||||
STACK_OF(GENERAL_NAME) *values;
|
STACK_OF(GENERAL_NAME) *values;
|
||||||
int count;
|
int j, count;
|
||||||
|
|
||||||
extension = X509_get_ext(crt, i);
|
if ((extension = X509_get_ext(crt, i)) == NULL)
|
||||||
if (extension == NULL)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
values = X509V3_EXT_d2i(extension);
|
if ((values = X509V3_EXT_d2i(extension)) == NULL)
|
||||||
if (values == NULL)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
count = sk_GENERAL_NAME_num(values);
|
count = sk_GENERAL_NAME_num(values);
|
||||||
for (j = 0; j < count; j++) {
|
for (j = 0; j < count; j++) {
|
||||||
GENERAL_NAME *generalName;
|
GENERAL_NAME *generalName;
|
||||||
|
OFList *list;
|
||||||
|
|
||||||
generalName = sk_GENERAL_NAME_value(values, j);
|
generalName = sk_GENERAL_NAME_value(values, j);
|
||||||
|
|
||||||
switch(generalName->type) {
|
switch(generalName->type) {
|
||||||
case GEN_OTHERNAME: {
|
case GEN_OTHERNAME:;
|
||||||
OTHERNAME *otherName = generalName->d.otherName;
|
OTHERNAME *otherName = generalName->d.otherName;
|
||||||
OFMutableDictionary *types;
|
OFMutableDictionary *types;
|
||||||
OFList *list;
|
|
||||||
OFString *key;
|
OFString *key;
|
||||||
|
|
||||||
types = [ret objectForKey: @"otherName"];
|
types = [ret objectForKey: @"otherName"];
|
||||||
if (types == nil) {
|
if (types == nil) {
|
||||||
types
|
types =
|
||||||
= [OFMutableDictionary dictionary];
|
[OFMutableDictionary dictionary];
|
||||||
[ret setObject: types
|
[ret setObject: types
|
||||||
forKey: @"otherName"];
|
forKey: @"otherName"];
|
||||||
}
|
}
|
||||||
|
@ -178,10 +186,7 @@
|
||||||
[self X509_stringFromASN1String:
|
[self X509_stringFromASN1String:
|
||||||
otherName->value->value.asn1_string]];
|
otherName->value->value.asn1_string]];
|
||||||
break;
|
break;
|
||||||
}
|
case GEN_EMAIL:
|
||||||
case GEN_EMAIL: {
|
|
||||||
OFList *list;
|
|
||||||
|
|
||||||
list = [ret objectForKey: @"rfc822Name"];
|
list = [ret objectForKey: @"rfc822Name"];
|
||||||
if (list == nil) {
|
if (list == nil) {
|
||||||
list = [OFList list];
|
list = [OFList list];
|
||||||
|
@ -193,10 +198,7 @@
|
||||||
[self X509_stringFromASN1String:
|
[self X509_stringFromASN1String:
|
||||||
generalName->d.rfc822Name]];
|
generalName->d.rfc822Name]];
|
||||||
break;
|
break;
|
||||||
}
|
case GEN_DNS:
|
||||||
case GEN_DNS: {
|
|
||||||
OFList *list;
|
|
||||||
|
|
||||||
list = [ret objectForKey: @"dNSName"];
|
list = [ret objectForKey: @"dNSName"];
|
||||||
if (list == nil) {
|
if (list == nil) {
|
||||||
list = [OFList list];
|
list = [OFList list];
|
||||||
|
@ -207,50 +209,45 @@
|
||||||
[self X509_stringFromASN1String:
|
[self X509_stringFromASN1String:
|
||||||
generalName->d.dNSName]];
|
generalName->d.dNSName]];
|
||||||
break;
|
break;
|
||||||
}
|
case GEN_URI:
|
||||||
case GEN_URI: {
|
|
||||||
OFList *list;
|
|
||||||
|
|
||||||
list = [ret objectForKey:
|
list = [ret objectForKey:
|
||||||
@"uniformResourceIdentifier"];
|
@"uniformResourceIdentifier"];
|
||||||
if (list == nil) {
|
if (list == nil) {
|
||||||
list = [OFList list];
|
list = [OFList list];
|
||||||
[ret setObject: list
|
[ret setObject: list
|
||||||
forKey:
|
forKey: @"uniformResource"
|
||||||
@"uniformResourceIdentifier"];
|
@"Identifier"];
|
||||||
}
|
}
|
||||||
[list appendObject:
|
[list appendObject:
|
||||||
[self X509_stringFromASN1String:
|
[self X509_stringFromASN1String:
|
||||||
generalName->d.uniformResourceIdentifier]];
|
generalName->d.uniformResourceIdentifier]];
|
||||||
break;
|
break;
|
||||||
}
|
case GEN_IPADD:
|
||||||
case GEN_IPADD: {
|
|
||||||
OFList *list;
|
|
||||||
|
|
||||||
list = [ret objectForKey: @"iPAddress"];
|
list = [ret objectForKey: @"iPAddress"];
|
||||||
if (list == nil) {
|
if (list == nil) {
|
||||||
list = [OFList list];
|
list = [OFList list];
|
||||||
[ret setObject: list
|
[ret setObject: list
|
||||||
forKey: @"iPAddress"];
|
forKey: @"iPAddress"];
|
||||||
}
|
}
|
||||||
[list appendObject:
|
[list appendObject: [self
|
||||||
[self X509_stringFromASN1String:
|
X509_stringFromASN1String:
|
||||||
generalName->d.iPAddress]];
|
generalName->d.iPAddress]];
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i++; /* Next extension */
|
i++; /* Next extension */
|
||||||
|
[pool releaseObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
[ret makeImmutable];
|
|
||||||
[ret retain];
|
|
||||||
[pool release];
|
[pool release];
|
||||||
|
|
||||||
return (subjectAlternativeName = ret);
|
[ret makeImmutable];
|
||||||
|
subjectAlternativeName = [ret retain];
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)hasCommonNameMatchingDomain: (OFString*)domain
|
- (BOOL)hasCommonNameMatchingDomain: (OFString*)domain
|
||||||
|
@ -309,9 +306,8 @@
|
||||||
for (name in assertedNames) {
|
for (name in assertedNames) {
|
||||||
if ([name hasPrefix: service]) {
|
if ([name hasPrefix: service]) {
|
||||||
OFString *asserted;
|
OFString *asserted;
|
||||||
asserted = [name substringWithRange:
|
asserted = [name substringWithRange: of_range(
|
||||||
of_range(serviceLength,
|
serviceLength, [name length] - serviceLength)];
|
||||||
[name length] - serviceLength)];
|
|
||||||
if ([self X509_isAssertedDomain: asserted
|
if ([self X509_isAssertedDomain: asserted
|
||||||
equalDomain: domain]) {
|
equalDomain: domain]) {
|
||||||
[pool release];
|
[pool release];
|
||||||
|
@ -324,8 +320,8 @@
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) X509_isAssertedDomain: (OFString*)asserted
|
- (BOOL)X509_isAssertedDomain: (OFString*)asserted
|
||||||
equalDomain: (OFString*)domain
|
equalDomain: (OFString*)domain
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In accordance with RFC 6125 this only allows a wildcard as the
|
* In accordance with RFC 6125 this only allows a wildcard as the
|
||||||
|
@ -333,21 +329,24 @@
|
||||||
* E.g. *.example.com matches foo.example.com,
|
* E.g. *.example.com matches foo.example.com,
|
||||||
* but not foo.bar.example.com
|
* but not foo.bar.example.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t firstDot;
|
size_t firstDot;
|
||||||
if (![asserted caseInsensitiveCompare: domain])
|
|
||||||
|
if ([asserted caseInsensitiveCompare: domain] == OF_ORDERED_SAME)
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
if (![asserted hasPrefix: @"*."])
|
if (![asserted hasPrefix: @"*."])
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
asserted = [asserted substringWithRange: of_range(2,
|
asserted = [asserted substringWithRange:
|
||||||
[asserted length] - 2)];
|
of_range(2, [asserted length] - 2)];
|
||||||
|
|
||||||
firstDot = [domain indexOfFirstOccurrenceOfString: @"."];
|
firstDot = [domain indexOfFirstOccurrenceOfString: @"."];
|
||||||
if (firstDot == OF_INVALID_INDEX)
|
if (firstDot == OF_INVALID_INDEX)
|
||||||
return NO;
|
return NO;
|
||||||
domain = [domain substringWithRange: of_range(firstDot + 1,
|
|
||||||
[domain length] - firstDot - 1)];
|
domain = [domain substringWithRange:
|
||||||
|
of_range(firstDot + 1, [domain length] - firstDot - 1)];
|
||||||
|
|
||||||
if (![asserted caseInsensitiveCompare: domain])
|
if (![asserted caseInsensitiveCompare: domain])
|
||||||
return YES;
|
return YES;
|
||||||
|
@ -357,10 +356,9 @@
|
||||||
|
|
||||||
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name
|
- (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int count = X509_NAME_entry_count(name);
|
|
||||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
|
||||||
OFMutableDictionary *dict = [OFMutableDictionary dictionary];
|
OFMutableDictionary *dict = [OFMutableDictionary dictionary];
|
||||||
|
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||||
|
int i, count = X509_NAME_entry_count(name);
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
OFString *key, *value;
|
OFString *key, *value;
|
||||||
|
@ -375,39 +373,53 @@
|
||||||
|
|
||||||
value = [self X509_stringFromASN1String: str];
|
value = [self X509_stringFromASN1String: str];
|
||||||
[[dict objectForKey: key] appendObject: value];
|
[[dict objectForKey: key] appendObject: value];
|
||||||
|
|
||||||
|
[pool releaseObjects];
|
||||||
}
|
}
|
||||||
|
|
||||||
[dict makeImmutable];
|
|
||||||
[dict retain];
|
|
||||||
[pool release];
|
[pool release];
|
||||||
|
|
||||||
return [dict autorelease];
|
[dict makeImmutable];
|
||||||
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (OFString*)X509_stringFromASN1Object: (ASN1_OBJECT*)obj
|
- (OFString*)X509_stringFromASN1Object: (ASN1_OBJECT*)object
|
||||||
{
|
{
|
||||||
int len, buf_len = 256;
|
|
||||||
char *buf = [self allocMemoryWithSize: buf_len];
|
|
||||||
OFString *ret;
|
OFString *ret;
|
||||||
while ((len = OBJ_obj2txt(buf, buf_len, obj, 1)) > buf_len) {
|
int length, bufferLength = 256;
|
||||||
buf_len = len;
|
char *buffer = [self allocMemoryWithSize: bufferLength];
|
||||||
[self resizeMemory: buf
|
|
||||||
toSize: buf_len];
|
@try {
|
||||||
|
while ((length = OBJ_obj2txt(buffer, bufferLength, object,
|
||||||
|
1)) > bufferLength) {
|
||||||
|
bufferLength = length;
|
||||||
|
buffer = [self resizeMemory: buffer
|
||||||
|
toSize: bufferLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = [X509OID stringWithUTF8String: buffer];
|
||||||
|
} @finally {
|
||||||
|
[self freeMemory: buffer];
|
||||||
}
|
}
|
||||||
ret = [X509OID stringWithUTF8String: buf];
|
|
||||||
[self freeMemory: buf];
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (OFString*) X509_stringFromASN1String: (ASN1_STRING*)str
|
- (OFString*)X509_stringFromASN1String: (ASN1_STRING*)str
|
||||||
{
|
{
|
||||||
char *buf;
|
|
||||||
OFString *ret;
|
OFString *ret;
|
||||||
if (ASN1_STRING_to_UTF8((unsigned char**)&buf, str) < 0)
|
char *buffer;
|
||||||
|
|
||||||
|
if (ASN1_STRING_to_UTF8((unsigned char**)&buffer, str) < 0)
|
||||||
@throw [OFInvalidEncodingException exceptionWithClass: isa];
|
@throw [OFInvalidEncodingException exceptionWithClass: isa];
|
||||||
ret = [OFString stringWithUTF8String: buf];
|
|
||||||
OPENSSL_free(buf);
|
@try {
|
||||||
|
ret = [OFString stringWithUTF8String: buffer];
|
||||||
|
} @finally {
|
||||||
|
OPENSSL_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
Reference in a new issue