HTTPS/Client-authenticated

You are encouraged to solve this task according to the task description, using any language you may know.
Demonstrate how to connect to a web server over HTTPS where that server requires that the client present a certificate to prove who (s)he is. Unlike with the HTTPS request with authentication task, it is not acceptable to perform the authentication by a username/password or a set cookie.
This task is in general useful for use with webservice clients as it offers a high level of assurance that the client is an acceptable counterparty for the server. For example, Amazon Web Services uses this style of authentication.
r: request.get.certificate:"mycert.pem" "https://www.example.com" ø
using System;
using System.Net;
class Program
{
class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.ClientCertificates.Add(new X509Certificate());
return request;
}
}
static void Main(string[] args)
{
var client = new MyWebClient();
var data = client.DownloadString("https://example.com");
Console.WriteLine(data);
}
}
#ifdef __FB_WIN32__
#include once "win/winsock2.bi"
Declare Function fbsocket Alias "socket" (af As Long, Type As Long, protocol As Long) As SOCKET
#else
#include once "sys/socket.bi"
#include once "netinet/in.bi"
#include once "arpa/inet.bi"
#include once "netdb.bi"
Declare Function fbsocket Alias "socket" (af As Long, Type As Long, protocol As Long) As Long
#endif
Function main() As Integer
#ifdef __fb_win32__
Dim As WSADATA wsaData
WSAStartup(MAKEWORD(2, 2), @wsaData)
#endif
' Create socket
Dim As Long sock = fbsocket(AF_INET, SOCK_STREAM, 0)
' Get host info
Dim As hostent Ptr host = gethostbyname("www.example.com")
' Set up address structure
Dim As sockaddr_in addr
addr.sin_family = AF_INET
addr.sin_port = htons(443)
addr.sin_addr = *Cast(in_addr Ptr, host->h_addr)
' Connect
connect(sock, Cast(sockaddr Ptr, @addr), Sizeof(sockaddr_in))
' Send request
Dim As String request = "GET / HTTP/1.1" & Chr(13, 10) & _
"Host: www.example.com" & Chr(13, 10) & _
Chr(13, 10)
send(sock, request, Len(request), 0)
' Receive response
Dim As String response
Dim As String buffer = Space(4096)
Dim As Integer bytes
Do
bytes = recv(sock, buffer, 4096, 0)
If bytes > 0 Then response &= Left(buffer, bytes)
Loop While bytes > 0
Print response
' Cleanup
#ifdef __fb_win32__
closesocket(sock)
WSACleanup()
#Else
Close(sock)
#endif
Return 0
End Function
main()
Sleep
package main
import (
"crypto/tls"
"io/ioutil"
"log"
"net/http"
)
func main() {
// load key pair
cert, err := tls.LoadX509KeyPair(
"./client.local.tld/client.local.tld.crt",
"./client.local.tld/client.local.tld.key",
)
if err != nil {
log.Fatal("Error while loading x509 key pair", err)
}
// Create TLS Config in order to had client certificate
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}
// create http client with our custom transport with TLS config
client := &http.Client{Transport: transport}
res, err := client.Get("https://www.example.com/")
if err != nil {
log.Fatal(err)
}
contents, err := ioutil.ReadAll(res.Body)
log.Print(string(contents))
}
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.net.URI;
import java.net.URL;
import java.security.KeyStore;
import java.util.Scanner;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
public final class HTTPSClientAuthenticated {
public static void main(String[] aArgs) throws Exception {
final String keyStorePath = "the/path/to/keystore"; // The key store contains the client's certificate
final String keyStorePassword = "my-password";
SSLContext sslContext = getSSLContext(keyStorePath, keyStorePassword);
URL url = new URI("https://somehost.com").toURL();
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
// Obtain response from the url
BufferedInputStream response = (BufferedInputStream) connection.getInputStream();
try ( Scanner scanner = new Scanner(response) ) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
}
private static SSLContext getSSLContext(String aPath, String aPassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load( new FileInputStream(aPath), aPassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
keyManagerFactory.init(keyStore, aPassword.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
return sslContext;
}
}
using HTTP, MbedTLS
conf = MbedTLS.SSLConfig(true, log_secrets="/utl/secret_key_log.log")
resp = HTTP.get("https://httpbin.org/ip", sslconfig=conf)
println(resp)
- Output:
HTTP.Messages.Response: """ HTTP/1.1 200 OK Connection: keep-alive Server: gunicorn/19.9.0 Date: Wed, 28 Nov 2018 08:42:25 GMT Content-Type: application/json Content-Length: 30 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Via: 1.1 vegur
{
"origin": "104.28.10.103"} """
// version 1.2.0
import java.security.KeyStore
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.HttpsURLConnection
import java.net.URL
import java.io.FileInputStream
import java.io.InputStreamReader
import java.io.BufferedReader
fun getSSLContext(p12Path: String, password: String): SSLContext {
val ks = KeyStore.getInstance("pkcs12")
val fis = FileInputStream(p12Path)
val pwd = password.toCharArray()
ks.load(fis, pwd)
val kmf = KeyManagerFactory.getInstance("PKIX")
kmf.init(ks, pwd)
val sc = SSLContext.getInstance("TLS")
sc.init(kmf.keyManagers, null, null)
return sc
}
fun main(args: Array<String>) {
// The .p12 file contains the client certificate and private key
val sc = getSSLContext("whatever.p12", "password")
val url = URL("https://somehost.com")
val con = url.openConnection() as HttpsURLConnection
con.sslSocketFactory = sc.socketFactory
val isr = InputStreamReader(con.inputStream)
val br = BufferedReader(isr)
while (true) {
val line = br.readLine()
if (line == null) break
println(line)
}
}
local(sslcert = file('myCert.pem'))
local(x = curl('https://sourceforge.net'))
#x->set(CURLOPT_SSLCERT, #sslcert->readstring)
#sslcert->close
#x->result->asString
a = RunThrough["curl -E myCert.pem https://www.example.com", 1]
For[ i=0, i < Length[a] , i++, SomeFunction[a]]
import httpclient, net
var client = newHttpClient(sslContext = newContext(certFile = "mycert.pem"))
var r = client.get("https://www.example.com")
class Test {
function : Main(args : String[]) ~ Nil {
url := Web.HTTP.Url->New("https://www.example.com");
pem := "C:/Users/reality/deploy-arm64/lib/cacert.pem";
Web.HTTP.HttpsClient->QuickGet(url, "text/html", Nil, pem)->GetContent()->PrintLine();
}
}#!/usr/bin/env perl -T
use 5.018_002;
use warnings;
use LWP;
our $VERSION = 1.000_000;
my $ua = LWP::UserAgent->new(
ssl_opts => {
SSL_cert_file => 'certificate.pem',
SSL_key_file => 'key.pem',
verify_hostname => 1,
}
);
my $req = HTTP::Request->new( GET => 'https://www.example.com' );
my $res = $ua->request($req);
if ( $res->is_success ) {
say $res->content;
}
else {
say $res->status_line;
}
Exactly the same as the HTTP#Phix task, except for the CURLOPT_SSLCERT part.
without js include builtins\libcurl.e curl_global_init() atom curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_URL, "https://sourceforge.net") integer fn = open("myCert.pem","r") curl_easy_setopt(curl, CURLOPT_SSLCERT, get_text(fn)) close(fn) object res = curl_easy_perform_ex(curl) curl_easy_cleanup(curl) curl_global_cleanup() puts(1,res)
(in '(curl "-E" "myCert.pem" "https://www.example.com")
(while (line)
(doSomeProcessingWithLine @) ) )import httplib
connection = httplib.HTTPSConnection('www.example.com',cert_file='myCert.PEM')
connection.request('GET','/index.html')
response = connection.getresponse()
data = response.read()
Skeleton code to connect to a server:
#lang racket
(require openssl/mzssl)
(define ctx (ssl-make-client-context))
(ssl-set-verify! ctx #t) ; verify the connection
(ssl-load-verify-root-certificates! ctx "my-cert.pem")
(define-values [I O] (ssl-connect "www.example.com" 443 ctx))
(formerly Perl 6)
# cert creation commands
# openssl req -newkey rsa:4096 -keyout my_key.pem -out my_csr.pem -nodes -subj "/CN=ME"
# openssl x509 -req -in my_csr.pem -signkey my_key.pem -out my_cert.pem
use v6;
use OpenSSL;
my $host = "github.com";
my $ssl = OpenSSL.new(:client);
$ssl.use-certificate-file("./my_cert.pem");
$ssl.use-privatekey-file("./my_key.pem");
$ssl.check-private-key;
my $s = IO::Socket::INET.new(:$host, :port(443));
$ssl.set-socket($s);
$ssl.set-connect-state;
$ssl.connect;
$ssl.write("GET / HTTP/1.1\r\n\r\n");
say $ssl.read(1024);
$ssl.close;
$s.close;
require 'uri'
require 'net/http'
uri = URI.parse('https://www.example.com')
pem = File.read("/path/to/my.pem")
cert = OpenSSL::X509::Certificate.new(pem)
key = OpenSSL::PKey::RSA.new(pem)
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
cert: cert, key: key) do |http|
request = Net::HTTP::Get.new uri
http.request request
end
This implementation uses reqwest, the de facto standard high-level HTTP(S) rust library. It is roughly equivalent in purpose and functionality to Python's requests.
Cargo.toml dependencies
The blocking variant of the reqwest library is used here for simplicity's sake. An asynchronous API is also available.
Native (system) TLS libraries are used instead of Rustls, the Rust TLS implementation, because we use a PKCS#12 certificate which at the time of writing does not seem to be available on Rustls. A PKCS#12 certificate is used instead of its PEM equivalent because reading password-protected PEM files does not seem to be available either.
reqwest = {version = "0.11", features = ["native-tls", "blocking"]}
src/main.rs
use std::fs::File;
use std::io::Read;
use reqwest::blocking::Client;
use reqwest::Identity;
fn main() -> std::io::Result<()> {
let identity = {
let mut buf = Vec::new();
// Downloaded from https://badssl.com/certs/badssl.com-client.p12
File::open("badssl.com-client.p12")?.read_to_end(&mut buf)?;
// Password is badssl.com
Identity::from_pkcs12_der(&buf, "badssl.com").unwrap()
};
let client = Client::builder().identity(identity).build().unwrap();
let response = client.get("https://client.badssl.com/").send().unwrap();
if !response.status().is_success() {
eprintln!("HTTP error requesting URL: {}", response.status());
}
println!("Got response from server: {}", response.text().unwrap());
Ok(())
}
import java.io.FileInputStream
import java.net.URL
import java.security.KeyStore
import javax.net.ssl.{HttpsURLConnection, KeyManagerFactory, SSLContext}
import scala.io.BufferedSource
object ClientAuthenticated extends App {
val con: HttpsURLConnection =
new URL("https://somehost.com").openConnection().asInstanceOf[HttpsURLConnection]
def getSSLContext(p12Path: String, password: String): SSLContext = {
val ks = KeyStore.getInstance("pkcs12")
val pwd = password.toCharArray
ks.load(new FileInputStream(p12Path), pwd)
val kmf = KeyManagerFactory.getInstance("PKIX")
kmf.init(ks, pwd)
val sc = SSLContext.getInstance("TLS")
sc.init(kmf.getKeyManagers, null, null)
sc
}
// The .p12 file contains the client certificate and private key
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLContext("whatever.p12", "password").getSocketFactory)
new BufferedSource(con.getInputStream).getLines.foreach(println(_))
}
Uses the Tls package.
package require http
package require tls
set cert myCert.p12
http::register https 443 [list \
::tls::socket -certfile $cert -password getPass]
proc getPass {} {
return "myPassword"; # Just a noddy example...
}
# Make a secure authenticated connection
set token [http::geturl https://verysecure.example.com/]
# Now as for conventional use of the “http” package
set data [http::data $token]
http::cleanup $token
This assumes the 'curl' command line utility is available on the system.
Uses the 'os' sub-module of Wren-std.
import "os" for Process
var certFile = "myCert.pem"
var keyFile = "myKey.pem"
var url = "www.example.com"
Process.exec("curl", ["--cert", certFile, "--key", keyFile, url])
Uses libCurl.
var CURL=Import("zklCurl"), c=CURL();
c.setOpt("SSLCERT","certFile.pem"); c.setOpt("SSLCERTTYPE","pem");
c.get("http://zenkinetic.com"); // lame example to show how to read- Programming Tasks
- Programming environment operations
- Networking and Web Interaction
- Arturo
- C sharp
- FreeBASIC
- Go
- Java
- Julia
- Kotlin
- Lasso
- Mathematica
- Wolfram Language
- Nim
- Objeck
- Perl
- Phix
- Phix/libcurl
- PicoLisp
- Python
- Racket
- Raku
- Ruby
- Rust
- Scala
- Tcl
- Wren
- Wren-std
- Zkl
- Batch File/Omit
- Brainf***/Omit
- Commodore BASIC/Omit
- EasyLang/Omit
- Inform 7/Omit
- Locomotive Basic/Omit
- Lotus 123 Macro Scripting/Omit
- Openscad/Omit
- M4/Omit
- Maxima/Omit
- ML/I/Omit
- PARI/GP/Omit
- PostScript/Omit
- Retro/Omit
- SQL PL/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Unlambda/Omit
- Yorick/Omit
- ZX Spectrum Basic/Omit