CCCertificate.m 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //
  2. // SPDX-FileCopyrightText: 2016 Marino Faggiana <m.faggiana@twsweb.it>, TWS
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. #import "CCCertificate.h"
  6. #import <openssl/x509.h>
  7. #import <openssl/bio.h>
  8. #import <openssl/err.h>
  9. #import <openssl/pem.h>
  10. #import "NCAppBranding.h"
  11. @implementation CCCertificate
  12. NSString *const appCertificates = @"Library/Application Support/Certificates";
  13. //Singleton
  14. + (CCCertificate *)sharedManager {
  15. static CCCertificate *CCCertificate = nil;
  16. static dispatch_once_t onceToken;
  17. dispatch_once(&onceToken, ^{
  18. CCCertificate = [[self alloc] init];
  19. });
  20. return CCCertificate;
  21. }
  22. static SecCertificateRef SecTrustGetLeafCertificate(SecTrustRef trust)
  23. // Returns the leaf certificate from a SecTrust object (that is always the
  24. // certificate at index 0).
  25. {
  26. SecCertificateRef result;
  27. assert(trust != NULL);
  28. if (SecTrustGetCertificateCount(trust) > 0) {
  29. result = SecTrustGetCertificateAtIndex(trust, 0);
  30. assert(result != NULL);
  31. } else {
  32. result = NULL;
  33. }
  34. return result;
  35. }
  36. - (BOOL)checkTrustedChallenge:(NSURLAuthenticationChallenge *)challenge
  37. {
  38. BOOL trusted = NO;
  39. SecTrustRef trust;
  40. NSURLProtectionSpace *protectionSpace;
  41. protectionSpace = [challenge protectionSpace];
  42. trust = [protectionSpace serverTrust];
  43. if(trust != nil) {
  44. [self saveCertificate:trust withName:@"tmp.der"];
  45. NSString *localCertificatesFolder = [self getDirectoryCerificates];
  46. NSArray* listCertificateLocation = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:localCertificatesFolder error:NULL];
  47. for (int i = 0 ; i < [listCertificateLocation count] ; i++) {
  48. NSString *currentLocalCertLocation = [NSString stringWithFormat:@"%@/%@",localCertificatesFolder,[listCertificateLocation objectAtIndex:i]];
  49. NSString *tempCertLocation = [NSString stringWithFormat:@"%@/%@",localCertificatesFolder,@"tmp.der"];
  50. NSFileManager *fileManager = [ NSFileManager defaultManager];
  51. if(![currentLocalCertLocation isEqualToString:tempCertLocation] &&
  52. [fileManager contentsEqualAtPath:tempCertLocation andPath:currentLocalCertLocation]) {
  53. NSLog(@"Certificated matched with one saved previously.");
  54. trusted = YES;
  55. }
  56. }
  57. } else {
  58. trusted = NO;
  59. }
  60. return trusted;
  61. }
  62. - (void)saveCertificate:(SecTrustRef)trust withName:(NSString *)certName
  63. {
  64. SecCertificateRef currentServerCert = SecTrustGetLeafCertificate(trust);
  65. CFDataRef data = SecCertificateCopyData(currentServerCert);
  66. X509 *x509cert = NULL;
  67. if (data) {
  68. BIO *mem = BIO_new_mem_buf((void *)CFDataGetBytePtr(data), (int)CFDataGetLength(data));
  69. x509cert = d2i_X509_bio(mem, NULL);
  70. BIO_free(mem);
  71. CFRelease(data);
  72. if (!x509cert) {
  73. NSLog(@"[LOG] OpenSSL couldn't parse X509 Certificate");
  74. } else {
  75. NSString *localCertificatesFolder = [self getDirectoryCerificates];
  76. certName = [NSString stringWithFormat:@"%@/%@",localCertificatesFolder,certName];
  77. if ([[NSFileManager defaultManager] fileExistsAtPath:certName]) {
  78. NSError *error;
  79. [[NSFileManager defaultManager] removeItemAtPath:certName error:&error];
  80. }
  81. FILE *file;
  82. file = fopen([certName UTF8String], "w");
  83. if (file) {
  84. PEM_write_X509(file, x509cert);
  85. }
  86. fclose(file);
  87. }
  88. } else {
  89. NSLog(@"[LOG] Failed to retrieve DER data from Certificate Ref");
  90. }
  91. //Free
  92. X509_free(x509cert);
  93. }
  94. - (void)presentViewControllerCertificateWithTitle:(NSString *)title viewController:(UIViewController *)viewController delegate:(id)delegate
  95. {
  96. if (![viewController isKindOfClass:[UIViewController class]])
  97. return;
  98. _delegate = delegate;
  99. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  100. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:NSLocalizedString(@"Do you want to connect to the server anyway?", nil) preferredStyle:UIAlertControllerStyleAlert];
  101. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"Yes", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  102. [[CCCertificate sharedManager] acceptCertificate];
  103. if([self.delegate respondsToSelector:@selector(trustedCerticateAccepted)])
  104. [self.delegate trustedCerticateAccepted];
  105. }]];
  106. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"No", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  107. if([self.delegate respondsToSelector:@selector(trustedCerticateDenied)])
  108. [self.delegate trustedCerticateDenied];
  109. }]];
  110. [viewController presentViewController:alertController animated:YES completion:nil];
  111. });
  112. }
  113. - (BOOL)acceptCertificate
  114. {
  115. NSString *localCertificatesFolder = [self getDirectoryCerificates];
  116. NSError *error;
  117. NSFileManager *fm = [[NSFileManager alloc] init];
  118. NSTimeInterval dateCertificate = [[NSDate date] timeIntervalSince1970];
  119. NSString *currentCertLocation = [NSString stringWithFormat:@"%@/%f.der",localCertificatesFolder, dateCertificate];
  120. NSLog(@"[LOG] currentCertLocation: %@", currentCertLocation);
  121. if(![fm moveItemAtPath:[NSString stringWithFormat:@"%@/%@",localCertificatesFolder, @"tmp.der"] toPath:currentCertLocation error:&error]) {
  122. NSLog(@"[LOG] Error: %@", [error localizedDescription]);
  123. return NO;
  124. }
  125. return YES;
  126. }
  127. - (NSString *)getDirectoryCerificates
  128. {
  129. NSURL *dirGroup = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupIdentifier];
  130. NSString *dir = [[dirGroup URLByAppendingPathComponent:appCertificates] path];
  131. if (![[NSFileManager defaultManager] fileExistsAtPath:dir])
  132. [[NSFileManager defaultManager] createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil];
  133. return dir;
  134. }
  135. @end