Index: src/X509Certificate.h ================================================================== --- src/X509Certificate.h +++ src/X509Certificate.h @@ -36,9 +36,10 @@ - initWithFile: (OFString*)file; - initWithStruct: (X509*)cert; - (OFDictionary*)issuer; - (OFDictionary*)subject; +- (OFDictionary*)subjectAlternativeName; - (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name; - (OFString*)X509_stringFromASN1Object: (ASN1_OBJECT*)obj; - (OFString*) X509_stringFromASN1String: (ASN1_STRING*)str; @end Index: src/X509Certificate.m ================================================================== --- src/X509Certificate.m +++ src/X509Certificate.m @@ -19,10 +19,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include +#include #import "X509Certificate.h" #import #import @@ -93,10 +94,138 @@ - (OFDictionary*)subject { X509_NAME *name = X509_get_subject_name(crt); return [self X509_dictionaryFromX509Name: name]; } + +- (OFDictionary*)subjectAlternativeName +{ + int i = -1, j; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + + while ((i = X509_get_ext_by_NID(crt, NID_subject_alt_name, i)) != -1) { + X509_EXTENSION *extension; + STACK_OF(GENERAL_NAME) *values; + int count; + + extension = X509_get_ext(crt, i); + if (extension == NULL) + break; + + values = X509V3_EXT_d2i(extension); + if (values == NULL) + break; + + count = sk_GENERAL_NAME_num(values); + for (j = 0; j < count; j++) { + GENERAL_NAME *generalName; + + generalName = sk_GENERAL_NAME_value(values, j); + + switch(generalName->type) { + case GEN_OTHERNAME: { + OTHERNAME *otherName = generalName->d.otherName; + OFMutableDictionary *types; + OFList *list; + OFString *key; + + types = [ret objectForKey: @"otherName"]; + if (types == nil) { + types + = [OFMutableDictionary dictionary]; + [ret setObject: types + forKey: @"otherName"]; + } + + key = [self X509_stringFromASN1Object: + otherName->type_id]; + list = [types objectForKey: key]; + if (list == nil) { + list = [OFList list]; + [types setObject: list + forKey: key]; + } + + [list appendObject: + [self X509_stringFromASN1String: + otherName->value->value.asn1_string]]; + break; + } + case GEN_EMAIL: { + OFList *list; + + list = [ret objectForKey: @"rfc822Name"]; + if (list == nil) { + list = [OFList list]; + [ret setObject: list + forKey: @"rfc822Name"]; + } + + [list appendObject: + [self X509_stringFromASN1String: + generalName->d.rfc822Name]]; + break; + } + case GEN_DNS: { + OFList *list; + + list = [ret objectForKey: @"dNSName"]; + if (list == nil) { + list = [OFList list]; + [ret setObject: list + forKey: @"dNSName"]; + } + [list appendObject: + [self X509_stringFromASN1String: + generalName->d.dNSName]]; + break; + } + case GEN_URI: { + OFList *list; + + list = [ret objectForKey: + @"uniformResourceIdentifier"]; + if (list == nil) { + list = [OFList list]; + [ret setObject: list + forKey: + @"uniformResourceIdentifier"]; + } + [list appendObject: + [self X509_stringFromASN1String: + generalName->d.uniformResourceIdentifier]]; + break; + } + case GEN_IPADD: { + OFList *list; + + list = [ret objectForKey: @"iPAddress"]; + if (list == nil) { + list = [OFList list]; + [ret setObject: list + forKey: @"iPAddress"]; + } + [list appendObject: + [self X509_stringFromASN1String: + generalName->d.iPAddress]]; + break; + } + default: + break; + } + } + + i++; /* Next extension */ + } + + [ret makeImmutable]; + [ret retain]; + [pool release]; + + return [ret autorelease]; +} - (OFDictionary*)X509_dictionaryFromX509Name: (X509_NAME*)name { int i; int count = X509_NAME_entry_count(name);