123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- //
- // CCCertificate.m
- // Crypto Cloud Technology Nextcloud
- //
- // Created by Marino Faggiana on 10/08/16.
- // Copyright (c) 2014 TWS. All rights reserved.
- //
- // Author Marino Faggiana <m.faggiana@twsweb.it>
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- #import "CCUtility.h"
- #import "CCCoreData.h"
- #import "CCCertificate.h"
- #import <openssl/x509.h>
- #import <openssl/bio.h>
- #import <openssl/err.h>
- #import <openssl/pem.h>
- @implementation CCCertificate
- //Singleton
- + (id)sharedManager {
- static CCCertificate *CCCertificate = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- CCCertificate = [[self alloc] init];
- });
- return CCCertificate;
- }
- static SecCertificateRef SecTrustGetLeafCertificate(SecTrustRef trust)
- // Returns the leaf certificate from a SecTrust object (that is always the
- // certificate at index 0).
- {
- SecCertificateRef result;
-
- assert(trust != NULL);
-
- if (SecTrustGetCertificateCount(trust) > 0) {
- result = SecTrustGetCertificateAtIndex(trust, 0);
- assert(result != NULL);
- } else {
- result = NULL;
- }
- return result;
- }
- - (BOOL)checkTrustedChallenge:(NSURLAuthenticationChallenge *)challenge
- {
- BOOL trusted = NO;
- SecTrustRef trust;
- NSURLProtectionSpace *protectionSpace;
-
- protectionSpace = [challenge protectionSpace];
- trust = [protectionSpace serverTrust];
-
- [CCUtility getDirectoryCerificates];
-
- if(trust != nil) {
-
- [self saveCertificate:trust withName:@"tmp.der"];
-
- NSString *localCertificatesFolder = [CCUtility getDirectoryCerificates];
-
- NSMutableArray *listCertificateLocation = [CCCoreData getAllCertificatesLocation];
-
- for (int i = 0 ; i < [listCertificateLocation count] ; i++) {
-
- NSString *currentLocalCertLocation = [listCertificateLocation objectAtIndex:i];
-
- NSFileManager *fileManager = [ NSFileManager defaultManager];
-
- if([fileManager contentsEqualAtPath:[NSString stringWithFormat:@"%@%@",localCertificatesFolder,@"tmp.der"] andPath:[NSString stringWithFormat:@"%@",currentLocalCertLocation]]) {
-
- NSLog(@"[LOG] Is the same certificate!!!");
- trusted = YES;
- }
- }
-
- } else
- trusted = NO;
-
- return trusted;
- }
- - (void)saveCertificate:(SecTrustRef)trust withName:(NSString *)certName
- {
- SecCertificateRef currentServerCert = SecTrustGetLeafCertificate(trust);
-
- CFDataRef data = SecCertificateCopyData(currentServerCert);
- X509 *x509cert = NULL;
- if (data) {
- BIO *mem = BIO_new_mem_buf((void *)CFDataGetBytePtr(data), (int)CFDataGetLength(data));
- x509cert = d2i_X509_bio(mem, NULL);
- BIO_free(mem);
- CFRelease(data);
-
- if (!x509cert) {
-
- NSLog(@"[LOG] OpenSSL couldn't parse X509 Certificate");
-
- } else {
-
- NSString *localCertificatesFolder = [CCUtility getDirectoryCerificates];
-
- certName = [NSString stringWithFormat:@"%@%@",localCertificatesFolder,certName];
-
- if ([[NSFileManager defaultManager] fileExistsAtPath:certName]) {
- NSError *error;
- [[NSFileManager defaultManager] removeItemAtPath:certName error:&error];
- }
-
- FILE *file;
- file = fopen([certName UTF8String], "w");
- if (file) {
- PEM_write_X509(file, x509cert);
- }
- fclose(file);
- }
-
- } else {
-
- NSLog(@"[LOG] Failed to retrieve DER data from Certificate Ref");
- }
-
- //Free
- X509_free(x509cert);
- }
- - (void)presentViewControllerCertificateWithTitle:(NSString *)title viewController:(UIViewController *)viewController delegate:(id)delegate
- {
- if (![viewController isKindOfClass:[UIViewController class]])
- return;
- //viewController = [[UIApplication sharedApplication] keyWindow].rootViewController;
-
- _delegate = delegate;
-
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:NSLocalizedString(@"_connect_server_anyway_", nil) preferredStyle:UIAlertControllerStyleAlert];
-
- [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_yes_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
-
- [[CCCertificate sharedManager] acceptCertificate];
-
- if([self.delegate respondsToSelector:@selector(trustedCerticateAccepted)])
- [self.delegate trustedCerticateAccepted];
- }]];
-
- [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_no_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
-
- if([self.delegate respondsToSelector:@selector(trustedCerticateDenied)])
- [self.delegate trustedCerticateDenied];
- }]];
-
- [viewController presentViewController:alertController animated:YES completion:nil];
- });
- }
- - (void)viewCertificate:(SecTrustRef)trust
- {
- SecCertificateRef currentServerCert = SecTrustGetLeafCertificate(trust);
-
- CFDataRef data = SecCertificateCopyData(currentServerCert);
- X509 *x509cert = NULL;
- if (data) {
- BIO *mem = BIO_new_mem_buf((void *)CFDataGetBytePtr(data), (int)CFDataGetLength(data));
- x509cert = d2i_X509_bio(mem, NULL);
- BIO_free(mem);
- CFRelease(data);
-
- if (!x509cert) {
-
- NSLog(@"[LOG] OpenSSL couldn't parse X509 Certificate");
-
- } else {
-
- NSString *issuer = CertificateGetIssuerName(x509cert);
- NSDate *expiryDate = CertificateGetExpiryDate(x509cert);
-
- NSLog(@"[LOG] %@ %@", issuer, expiryDate);
- }
-
- } else {
-
- NSLog(@"[LOG] Failed to retrieve DER data from Certificate Ref");
- }
-
- //Free
- X509_free(x509cert);
- }
- - (BOOL)acceptCertificate
- {
- NSString *localCertificatesFolder = [CCUtility getDirectoryCerificates];
- NSError *error;
- NSFileManager *fm = [[NSFileManager alloc] init];
- NSTimeInterval dateCertificate = [[NSDate date] timeIntervalSince1970];
- NSString *currentCertLocation = [NSString stringWithFormat:@"%@%f.der",localCertificatesFolder, dateCertificate];
-
- NSLog(@"[LOG] currentCertLocation: %@", currentCertLocation);
-
- if(![fm moveItemAtPath:[NSString stringWithFormat:@"%@%@",localCertificatesFolder, @"tmp.der"] toPath:currentCertLocation error:&error]) {
-
- NSLog(@"[LOG] Error: %@", [error localizedDescription]);
- return NO;
-
- } else {
-
- [CCCoreData addCertificate:[NSString stringWithFormat:@"%f.der", dateCertificate]];
- }
-
- return YES;
- }
- static NSString * CertificateGetIssuerName(X509 *certificateX509)
- {
- NSString *issuer = nil;
- if (certificateX509 != NULL) {
- X509_NAME *issuerX509Name = X509_get_issuer_name(certificateX509);
-
- if (issuerX509Name != NULL) {
- int nid = OBJ_txt2nid("O"); // organization
- int index = X509_NAME_get_index_by_NID(issuerX509Name, nid, -1);
-
- X509_NAME_ENTRY *issuerNameEntry = X509_NAME_get_entry(issuerX509Name, index);
-
- if (issuerNameEntry) {
- ASN1_STRING *issuerNameASN1 = X509_NAME_ENTRY_get_data(issuerNameEntry);
-
- if (issuerNameASN1 != NULL) {
- unsigned char *issuerName = ASN1_STRING_data(issuerNameASN1);
- issuer = [NSString stringWithUTF8String:(char *)issuerName];
- }
- }
- }
- }
-
- return issuer;
- }
- static NSDate *CertificateGetExpiryDate(X509 *certificateX509)
- {
- NSDate *expiryDate = nil;
-
- if (certificateX509 != NULL) {
- ASN1_TIME *certificateExpiryASN1 = X509_get_notAfter(certificateX509);
- if (certificateExpiryASN1 != NULL) {
- ASN1_GENERALIZEDTIME *certificateExpiryASN1Generalized = ASN1_TIME_to_generalizedtime(certificateExpiryASN1, NULL);
- if (certificateExpiryASN1Generalized != NULL) {
- unsigned char *certificateExpiryData = ASN1_STRING_data(certificateExpiryASN1Generalized);
-
- // ASN1 generalized times look like this: "20131114230046Z"
- // format: YYYYMMDDHHMMSS
- // indices: 01234567890123
- // 1111
- // There are other formats (e.g. specifying partial seconds or
- // time zones) but this is good enough for our purposes since
- // we only use the date and not the time.
- //
- // (Source: http://www.obj-sys.com/asn1tutorial/node14.html)
-
- NSString *expiryTimeStr = [NSString stringWithUTF8String:(char *)certificateExpiryData];
- NSDateComponents *expiryDateComponents = [[NSDateComponents alloc] init];
-
- expiryDateComponents.year = [[expiryTimeStr substringWithRange:NSMakeRange(0, 4)] intValue];
- expiryDateComponents.month = [[expiryTimeStr substringWithRange:NSMakeRange(4, 2)] intValue];
- expiryDateComponents.day = [[expiryTimeStr substringWithRange:NSMakeRange(6, 2)] intValue];
- expiryDateComponents.hour = [[expiryTimeStr substringWithRange:NSMakeRange(8, 2)] intValue];
- expiryDateComponents.minute = [[expiryTimeStr substringWithRange:NSMakeRange(10, 2)] intValue];
- expiryDateComponents.second = [[expiryTimeStr substringWithRange:NSMakeRange(12, 2)] intValue];
-
- NSCalendar *calendar = [NSCalendar currentCalendar];
- expiryDate = [calendar dateFromComponents:expiryDateComponents];
- }
- }
- }
-
- return expiryDate;
- }
- @end
|