From bdc8d1ad5364e0e52c2a7b87fedd23955f91b59b Mon Sep 17 00:00:00 2001 From: msweet Date: Tue, 15 Jul 2014 14:01:27 +0000 Subject: [PATCH] Fix load/save of certificates. Implement peer certificates. Validation now works for GNU TLS (STR #1616) git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@12028 a1ca3aef-8c08-0410-bb20-df032aa958be --- cups/testhttp.c | 25 ++++++++++++++++++++ cups/tls-gnutls.c | 59 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/cups/testhttp.c b/cups/testhttp.c index 00b46de12..808aa4dd5 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -627,15 +627,40 @@ main(int argc, /* I - Number of command-line arguments */ static const char *trusts[] = { "OK", "Invalid", "Changed", "Expired", "Renewed", "Unknown" }; if (!httpCopyCredentials(http, &creds)) { + cups_array_t *lcreds; http_trust_t trust = httpCredentialsGetTrust(creds, hostname); httpCredentialsString(creds, info, sizeof(info)); + printf("Count: %d\n", cupsArrayCount(creds)); printf("Trust: %s\n", trusts[trust]); printf("Expiration: %s\n", httpGetDateString(httpCredentialsGetExpiration(creds))); printf("IsValidName: %d\n", httpCredentialsAreValidForName(creds, hostname)); printf("String: \"%s\"\n", info); + printf("LoadCredentials: %d\n", httpLoadCredentials(NULL, &lcreds, hostname)); + httpCredentialsString(lcreds, info, sizeof(info)); + printf(" Count: %d\n", cupsArrayCount(lcreds)); + printf(" String: \"%s\"\n", info); + + if (lcreds && cupsArrayCount(creds) == cupsArrayCount(lcreds)) + { + int i; + http_credential_t *cred, *lcred; + + for (i = 1, cred = (http_credential_t *)cupsArrayFirst(creds), lcred = (http_credential_t *)cupsArrayFirst(lcreds); + cred && lcred; + i ++, cred = (http_credential_t *)cupsArrayNext(creds), lcred = (http_credential_t *)cupsArrayNext(lcreds)) + { + if (cred->datalen != lcred->datalen) + printf(" Credential #%d: Different lengths (saved=%d, current=%d)\n", i, (int)cred->datalen, (int)lcred->datalen); + else if (memcmp(cred->data, lcred->data, cred->datalen)) + printf(" Credential #%d: Different data\n", i); + else + printf(" Credential #%d: Matches\n", i); + } + } + if (trust != HTTP_TRUST_OK) { printf("SaveCredentials: %d\n", httpSaveCredentials(NULL, creds, hostname)); diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index a82eafbe2..abaeb3b5e 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -296,12 +296,33 @@ httpCopyCredentials( http_t *http, /* I - Connection to server */ cups_array_t **credentials) /* O - Array of credentials */ { + unsigned count; /* Number of certificates */ + const gnutls_datum_t *certs; /* Certificates */ + + + DEBUG_printf(("httpCopyCredentials(http=%p, credentials=%p)", http, credentials)); + if (credentials) *credentials = NULL; if (!http || !http->tls || !credentials) return (-1); + *credentials = cupsArrayNew(NULL, NULL); + certs = gnutls_certificate_get_peers(http->tls, &count); + + DEBUG_printf(("1httpCopyCredentials: certs=%p, count=%u", certs, count)); + + if (certs && count) + { + while (count > 0) + { + httpAddCredential(*credentials, certs->data, certs->size); + certs ++; + count --; + } + } + return (0); } @@ -467,7 +488,7 @@ httpCredentialsGetExpiration( cert = http_gnutls_create_credential((http_credential_t *)cupsArrayFirst(credentials)); if (cert) { - result = gnutls_x509_crt_get_expiration_time(cert, common_name); + result = gnutls_x509_crt_get_expiration_time(cert); gnutls_x509_crt_deinit(cert); } @@ -503,11 +524,15 @@ httpCredentialsString( (cert = http_gnutls_create_credential(first)) != NULL) { char name[256]; /* Common name associated with cert */ + size_t namelen; /* Length of name */ time_t expiration; /* Expiration date of cert */ _cups_md5_state_t md5_state; /* MD5 state */ unsigned char md5_digest[16]; /* MD5 result */ - if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, sizeof(name)) < 0) + namelen = sizeof(name) - 1; + if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &namelen) >= 0) + name[namelen] = '\0'; + else strlcpy(name, "unknown", sizeof(name)); expiration = gnutls_x509_crt_get_expiration_time(cert); @@ -629,8 +654,8 @@ httpLoadCredentials( } decoded = alloc_data - num_data; - httpDecode64_2(data, &decoded, line); - num_data += decoded; + httpDecode64_2((char *)data + num_data, &decoded, line); + num_data += (size_t)decoded; } } @@ -669,9 +694,9 @@ httpSaveCredentials( char filename[1024], /* filename.crt */ nfilename[1024],/* filename.crt.N */ temp[1024], /* Temporary string */ - line[61]; /* Base64-encoded line */ + line[256]; /* Base64-encoded line */ const unsigned char *ptr; /* Pointer into certificate */ - size_t remaining; /* Bytes left */ + ssize_t remaining; /* Bytes left */ http_credential_t *cred; /* Current credential */ @@ -696,9 +721,9 @@ httpSaveCredentials( cred = (http_credential_t *)cupsArrayNext(credentials)) { cupsFilePuts(fp, "-----BEGIN CERTIFICATE-----\n"); - for (ptr = cred->data, remaining = cred->datalen; remaining > 0; remaining -= 45, ptr += 45) + for (ptr = cred->data, remaining = (ssize_t)cred->datalen; remaining > 0; remaining -= 45, ptr += 45) { - httpEncode64_2(line, sizeof(line), ptr, remaining > 45 ? 45 : remaining); + httpEncode64_2(line, sizeof(line), (char *)ptr, remaining > 45 ? 45 : remaining); cupsFilePrintf(fp, "%s\n", line); } cupsFilePuts(fp, "-----END CERTIFICATE-----\n"); @@ -718,21 +743,29 @@ static gnutls_x509_crt_t /* O - Certificate */ http_gnutls_create_credential( http_credential_t *credential) /* I - Credential */ { - gnutls_crt_t cert; /* Certificate */ + int result; /* Result from GNU TLS */ + gnutls_x509_crt_t cert; /* Certificate */ gnutls_datum_t datum; /* Data record */ + DEBUG_printf(("3http_gnutls_create_credential(credential=%p)", credential)); + if (!credential) return (NULL); - if (gnutls_x509_crt_init(&cert) < 0) + if ((result = gnutls_x509_crt_init(&cert)) < 0) + { + DEBUG_printf(("4http_gnutls_create_credential: init error: %s", gnutls_strerror(result))); return (NULL); + } - datum.data = credential.data; - datum.size = credential.length; + datum.data = credential->data; + datum.size = credential->datalen; - if (gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_PEM) < 0) + if ((result = gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER)) < 0) { + DEBUG_printf(("4http_gnutls_create_credential: import error: %s", gnutls_strerror(result))); + gnutls_x509_crt_deinit(cert); return (NULL); } -- 2.39.2