AuthURLSessionTaskDelegate.m 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //
  2. // AuthURLSessionTaskDelegate.m
  3. // TunneledWebRequest
  4. //
  5. /*
  6. Licensed under Creative Commons Zero (CC0).
  7. https://creativecommons.org/publicdomain/zero/1.0/
  8. */
  9. // NOTE: this file is shared by TunneledWebRequest and TunneledWebView
  10. #import "AuthURLSessionTaskDelegate.h"
  11. #import "OCSP.h"
  12. #import "URLEncode.h"
  13. @implementation AuthURLSessionTaskDelegate
  14. - (id)initWithLogger:(void (^)(NSString*))logger andLocalHTTPProxyPort:(NSInteger)port{
  15. self = [super init];
  16. if (self) {
  17. self.logger = logger;
  18. self.localHTTPProxyPort = port;
  19. }
  20. return self;
  21. }
  22. - (void)logWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2) {
  23. if (self.logger != nil) {
  24. va_list arguments;
  25. va_start(arguments, format);
  26. NSString *message = [[NSString alloc] initWithFormat:format arguments:arguments];
  27. va_end(arguments);
  28. self.logger(message);
  29. }
  30. }
  31. - (void)URLSession:(NSURLSession *)session
  32. task:(NSURLSessionTask *)task
  33. didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
  34. completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
  35. {
  36. #pragma unused(session)
  37. #pragma unused(task)
  38. assert(challenge != nil);
  39. assert(completionHandler != nil);
  40. // Resolve NSURLAuthenticationMethodServerTrust ourselves
  41. if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
  42. [self logWithFormat:@"Got SSL certificate for %@, mainDocumentURL: %@, URL: %@",
  43. challenge.protectionSpace.host,
  44. [task.currentRequest mainDocumentURL],
  45. [task.currentRequest URL]];
  46. SecTrustRef trust = challenge.protectionSpace.serverTrust;
  47. if (trust == nil) {
  48. assert(NO);
  49. }
  50. SecPolicyRef policy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod |
  51. kSecRevocationRequirePositiveResponse |
  52. kSecRevocationNetworkAccessDisabled);
  53. SecTrustSetPolicies(trust, policy);
  54. CFRelease(policy);
  55. NSError *e;
  56. NSArray <NSURL*>* ocspURLs = [OCSP ocspURLs:trust error:&e];
  57. if (e != nil) {
  58. [self logWithFormat:@"Error constructing OCSP URLs: %@", e.localizedDescription];
  59. completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
  60. return;
  61. }
  62. if ([ocspURLs count] == 0) {
  63. [self logWithFormat:
  64. @"Error no OCSP URLs in the Certificate Authority Information Access "
  65. "(1.3.6.1.5.5.7.1.1) extension."];
  66. completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
  67. return;
  68. }
  69. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
  70. for (NSURL *ocspURL in ocspURLs) {
  71. // The target URL must be encoded, so as to be valid within a query parameter.
  72. NSString *encodedTargetUrl = [URLEncode encode:ocspURL.absoluteString];
  73. NSNumber *httpProxyPort = [NSNumber numberWithInt:
  74. (int)self.localHTTPProxyPort];
  75. NSString *proxiedURLString = [NSString stringWithFormat:@"http://127.0.0.1:%@"
  76. "/tunneled/%@",
  77. httpProxyPort,
  78. encodedTargetUrl];
  79. NSURL *proxiedURL = [NSURL URLWithString:proxiedURLString];
  80. if (proxiedURL == nil) {
  81. [self logWithFormat:@"Constructed invalid URL for OCSP request: %@",
  82. proxiedURLString];
  83. completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
  84. return;
  85. }
  86. NSURLRequest *ocspReq = [NSURLRequest requestWithURL:proxiedURL];
  87. NSURLResponse *resp = nil;
  88. NSError *e = nil;
  89. NSData *data = [NSURLConnection sendSynchronousRequest:ocspReq
  90. returningResponse:&resp
  91. error:&e];
  92. if (e != nil) {
  93. [self logWithFormat:@"Error with OCSP request: %@", e.localizedDescription];
  94. continue;
  95. }
  96. CFDataRef d = (__bridge CFDataRef)data;
  97. SecTrustSetOCSPResponse(trust, d);
  98. SecTrustResultType trustResultType;
  99. SecTrustEvaluate(trust, &trustResultType);
  100. if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultUnspecified) {
  101. NSURLCredential *credential = [NSURLCredential credentialForTrust:
  102. challenge.protectionSpace.serverTrust];
  103. assert(credential != nil);
  104. completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
  105. return;
  106. }
  107. completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
  108. return;
  109. }
  110. });
  111. return;
  112. }
  113. completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
  114. }
  115. @end