HTTPS/Client-authenticated: Difference between revisions

From Rosetta Code
Content added Content deleted
(implement in nim-lang)
(Added Wren)
Line 318: Line 318:
set data [http::data $token]
set data [http::data $token]
http::cleanup $token</lang>
http::cleanup $token</lang>

=={{header|Wren}}==
{{trans|C}}
{{libheader|libcurl}}
An embedded program so we can ask the C host to communicate with libcurl for us.
<lang ecmascript>/* https_client-authenticated.wren */

var CURLOPT_URL = 10002
var CURLOPT_SSLCERT = 10025
var CURLOPT_SSLKEY = 10087
var CURLOPT_KEYPASSWD = 10258

foreign class Curl {
construct easyInit() {}

foreign easySetOpt(opt, param)

foreign easyPerform()

foreign easyCleanup()
}

var curl = Curl.easyInit()
if (curl == 0) {
System.print("Error initializing cURL.")
return
}

curl.easySetOpt(CURLOPT_URL, "https://example.com/")
curl.easySetOpt(CURLOPT_SSLCERT, "cert.pem")
curl.easySetOpt(CURLOPT_SSLKEY, "key.pem")
curl.easySetOpt(CURLOPT_KEYPASSWD, "s3cret")

var status = curl.easyPerform()
if (status != 0) {
System.print("Failed to perform task.")
return
}
curl.easyCleanup()</lang>
<br>
We now embed this in the following C program, compile and run it.
<lang c>/* gcc https_client-authenticated.c -o https_client-authenticated -lcurl -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}

void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLcode cc = curl_easy_perform(curl);
wrenSetSlotDouble(vm, 0, (double)cc);
}

void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}

void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
const char *arg = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, arg);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}

WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}

char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}

int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "https_client-authenticated.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</lang>


=={{header|zkl}}==
=={{header|zkl}}==

Revision as of 16:52, 5 October 2021

Task
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.

C#

Works with: C sharp version 3.0

<lang csharp> 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);
   }

} </lang>

Go

<lang Go>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))

} </lang>

Julia

<lang julia>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)

</lang>

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"

} """

Kotlin

<lang scala>// 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)
   }

}</lang>

Lasso

<lang Lasso>local(sslcert = file('myCert.pem')) local(x = curl('https://sourceforge.net'))

  1. x->set(CURLOPT_SSLCERT, #sslcert->readstring)
  2. sslcert->close
  3. x->result->asString</lang>

Mathematica / Wolfram Language

<lang Mathematica>a = RunThrough["curl -E myCert.pem https://www.example.com", 1] For[ i=0, i < Length[a] , i++, SomeFunction[a]]</lang>

Nim

<lang nim>import httpclient, net var client = newHttpClient(sslContext = newContext(certFile = "mycert.pem")) var r = client.get("https://www.example.com")</lang>

Perl

<lang python>#!/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;

}</lang>

Phix

Library: Phix/libcurl

Exactly the same as the HTTP#Phix task, except for the CURLOPT_SSLCERT part. <lang Phix>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)</lang>

PicoLisp

<lang PicoLisp>(in '(curl "-E" "myCert.pem" "https://www.example.com")

  (while (line)
     (doSomeProcessingWithLine @) ) )</lang>

Python

<lang python>import httplib

connection = httplib.HTTPSConnection('www.example.com',cert_file='myCert.PEM') connection.request('GET','/index.html') response = connection.getresponse() data = response.read() </lang>

Racket

Skeleton code to connect to a server: <lang racket>

  1. 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)) </lang>

Raku

(formerly Perl 6) <lang perl6>

  1. cert creation commands
  1. openssl req -newkey rsa:4096 -keyout my_key.pem -out my_csr.pem -nodes -subj "/CN=ME"
  1. 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;

</lang>

Ruby

<lang Ruby>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</lang>

Scala

<lang Scala>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(_))

}</lang>

Tcl

Uses the Tls package. <lang tcl>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...

}

  1. Make a secure authenticated connection

set token [http::geturl https://verysecure.example.com/]

  1. Now as for conventional use of the “http” package

set data [http::data $token] http::cleanup $token</lang>

Wren

Translation of: C
Library: libcurl

An embedded program so we can ask the C host to communicate with libcurl for us. <lang ecmascript>/* https_client-authenticated.wren */

var CURLOPT_URL = 10002 var CURLOPT_SSLCERT = 10025 var CURLOPT_SSLKEY = 10087 var CURLOPT_KEYPASSWD = 10258

foreign class Curl {

   construct easyInit() {}
   foreign easySetOpt(opt, param)
   foreign easyPerform()
   foreign easyCleanup()

}

var curl = Curl.easyInit() if (curl == 0) {

   System.print("Error initializing cURL.")
   return

}

curl.easySetOpt(CURLOPT_URL, "https://example.com/") curl.easySetOpt(CURLOPT_SSLCERT, "cert.pem") curl.easySetOpt(CURLOPT_SSLKEY, "key.pem") curl.easySetOpt(CURLOPT_KEYPASSWD, "s3cret")

var status = curl.easyPerform() if (status != 0) {

   System.print("Failed to perform task.")
   return

} curl.easyCleanup()</lang>
We now embed this in the following C program, compile and run it. <lang c>/* gcc https_client-authenticated.c -o https_client-authenticated -lcurl -lwren -lm */

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  4. include <curl/curl.h>
  5. include "wren.h"

/* C <=> Wren interface functions */

void C_curlAllocate(WrenVM* vm) {

   CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
   *pcurl = curl_easy_init();

}

void C_easyPerform(WrenVM* vm) {

   CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
   CURLcode cc = curl_easy_perform(curl);
   wrenSetSlotDouble(vm, 0, (double)cc);

}

void C_easyCleanup(WrenVM* vm) {

   CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
   curl_easy_cleanup(curl);

}

void C_easySetOpt(WrenVM* vm) {

   CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
   CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
   const char *arg = wrenGetSlotString(vm, 2);
   curl_easy_setopt(curl, opt, arg);

}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {

   WrenForeignClassMethods methods;
   methods.allocate = NULL;
   methods.finalize = NULL;
   if (strcmp(module, "main") == 0) {
       if (strcmp(className, "Curl") == 0) {
           methods.allocate = C_curlAllocate;
       }
   }
   return methods;

}

WrenForeignMethodFn bindForeignMethod(

   WrenVM* vm,
   const char* module,
   const char* className,
   bool isStatic,
   const char* signature) {
   if (strcmp(module, "main") == 0) {
       if (strcmp(className, "Curl") == 0) {
           if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
           if (!isStatic && strcmp(signature, "easyPerform()") == 0)   return C_easyPerform;
           if (!isStatic && strcmp(signature, "easyCleanup()") == 0)   return C_easyCleanup;
       }
   }
   return NULL;

}

static void writeFn(WrenVM* vm, const char* text) {

   printf("%s", text);

}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {

   switch (errorType) {
       case WREN_ERROR_COMPILE:
           printf("[%s line %d] [Error] %s\n", module, line, msg);
           break;
       case WREN_ERROR_STACK_TRACE:
           printf("[%s line %d] in %s\n", module, line, msg);
           break;
       case WREN_ERROR_RUNTIME:
           printf("[Runtime Error] %s\n", msg);
           break;
   }

}

char *readFile(const char *fileName) {

   FILE *f = fopen(fileName, "r");
   fseek(f, 0, SEEK_END);
   long fsize = ftell(f);
   rewind(f);
   char *script = malloc(fsize + 1);
   fread(script, 1, fsize, f);
   fclose(f);
   script[fsize] = 0;
   return script;

}

int main(int argc, char **argv) {

   WrenConfiguration config;
   wrenInitConfiguration(&config);
   config.writeFn = &writeFn;
   config.errorFn = &errorFn;
   config.bindForeignClassFn = &bindForeignClass;
   config.bindForeignMethodFn = &bindForeignMethod;
   WrenVM* vm = wrenNewVM(&config);
   const char* module = "main";
   const char* fileName = "https_client-authenticated.wren";
   char *script = readFile(fileName);
   WrenInterpretResult result = wrenInterpret(vm, module, script);
   switch (result) {
       case WREN_RESULT_COMPILE_ERROR:
           printf("Compile Error!\n");
           break;
       case WREN_RESULT_RUNTIME_ERROR:
           printf("Runtime Error!\n");
           break;
       case WREN_RESULT_SUCCESS:
           break;
   }
   wrenFreeVM(vm);
   free(script);
   return 0;

}</lang>

zkl

Uses libCurl. <lang zkl>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</lang>