1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
# sanity check to make sure we're looking at an ASCII armored cert
validateCertificate <- function(certificate) {
return(any(grepl("-----BEGIN CERTIFICATE-----", certificate, fixed = TRUE)))
}
createCertificateFile <- function(certificate) {
certificateFile <- NULL
# check the R option first, then fall back on the environment variable
systemStore <- getOption("rsconnect.ca.bundle")
if (is.null(systemStore) || !nzchar(systemStore)) {
systemStore <- Sys.getenv("RSCONNECT_CA_BUNDLE")
}
# start by checking for a cert file specified in an environment variable
if (!is.null(systemStore) && nzchar(systemStore)) {
if (file.exists(systemStore)) {
certificateFile <- systemStore
} else {
warning("The certificate store '", systemStore, "' specified in the ",
if (identical(systemStore, getOption("rsconnect.ca.bundle")))
"rsconnect.ca.bundle option "
else
"RSCONNECT_CA_BUNDLE environment variable ",
"does not exist. The system certificate store will be used instead.")
}
}
# if no certificate contents specified, we're done
if (is.null(certificate))
return(certificateFile)
# if we don't have a certificate file yet, try to find the system store
if (is.null(certificateFile)) {
if (.Platform$OS.type == "unix") {
# search known locations on Unix-like
stores <- c("/etc/ssl/certs/ca-certificates.crt",
"/etc/pki/tls/certs/ca-bundle.crt",
"/usr/share/ssl/certs/ca-bundle.crt",
"/usr/local/share/certs/ca-root.crt",
"/etc/ssl/cert.pem",
"/var/lib/ca-certificates/ca-bundle.pem")
} else {
# mirror behavior of curl on Windows, which looks in system folders,
# the working directory, and %PATH%.
stores <- c(file.path(getwd(), "curl-ca-bundle.crt"),
"C:/Windows/System32/curl-ca-bundle.crt",
"C:/Windows/curl-ca-bundle.crt",
file.path(strsplit(Sys.getenv("PATH"), ";", fixed = TRUE),
"curl-ca-bundle.crt"))
}
# use our own baked-in bundle as a last resort
stores <- c(stores, system.file(package = "rsconnect", "cert", "cacert.pem"))
for (store in stores) {
if (file.exists(store)) {
# if the bundle exists, stop here
certificateFile <- store
break
}
}
# if we didn't find the system store, it's okay; the fact that we're here
# means that we have a server-specific certificate so it's probably going
# to be all right to use only that cert.
}
# create a temporary file to house the certificates
certificateStore <- tempfile(pattern = "cacerts", fileext = ".pem")
dirCreate(dirname(certificateStore))
file.create(certificateStore)
# open temporary cert store
con <- file(certificateStore, open = "at")
defer(close(con))
# copy the contents of the certificate file into the store, if we found one
# (we don't do a straight file copy since we don't want to inherit or
# correct permissions)
if (!is.null(certificateFile)) {
certLines <- readLines(certificateFile, warn = FALSE)
writeLines(text = certLines, con = con)
}
# append the server-specific certificate (with a couple of blank lines)
writeLines(text = c("", "", certificate), con = con)
return(certificateStore)
}
inferCertificateContents <- function(certificate) {
# certificate can be specified as either a character vector or a filename;
# infer which we're dealing with
# tolerate NULL, which is a valid case representing no certificate
if (is.null(certificate) || identical(certificate, ""))
return(NULL)
# collapse to a single string if we got a vector of lines
if (length(certificate) > 1)
certificate <- paste(certificate, collapse = "\n")
# looks like ASCII armored certificate data, return as-is
if (validateCertificate(substr(certificate, 1, 27)))
return(certificate)
# looks like a file; return its contents
if (file.exists(certificate)) {
if (file.size(certificate) > 1048576) {
stop("The file '", certificate, "' is too large. Certificate files must ",
"be less than 1MB.")
}
contents <- paste(readLines(con = certificate, warn = FALSE), collapse = "\n")
if (validateCertificate(contents))
return(contents)
else
stop("The file '", certificate, "' does not appear to be a certificate. ",
"Certificate files should be in ASCII armored PEM format, with a ",
"first line reading -----BEGIN CERTIFICATE-----.")
}
# doesn't look like something we can deal with; guess error based on length
if (nchar(certificate) < 200) {
stop("The certificate file '", certificate, "' does not exist.")
} else {
stop("The certificate '", substr(certificate, 1, 10), "...' is not ",
"correctly formed. Specify the certificate as either an ASCII armored string, ",
"beginning with -----BEGIN CERTIFICATE----, or a valid path to a file ",
"containing the certificate.")
}
}
|