├── NGINX ├── server.js ├── index.php └── site.nginx ├── NODEJS └── server.js ├── LICENSE └── README.md /NGINX/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | 4 | app.get('/nodejs', function (req, res) { 5 | let ou = req.headers.dn.split(':'); 6 | res.send(ou[0]); 7 | }); 8 | 9 | app.listen(3000, function () { 10 | console.log('Estamos utilizando a porta 3000!'); 11 | }); 12 | -------------------------------------------------------------------------------- /NGINX/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Page Title 7 | 8 | 9 | 10 |

Cerificado Digital ICP-Brasil

11 |
12 | 27 | 28 | -------------------------------------------------------------------------------- /NODEJS/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const fs = require('fs') 3 | const https = require('https') 4 | const app = express() 5 | 6 | const options = { 7 | key: fs.readFileSync('/etc/letsencrypt/live/meusite.com.br/privkey.pem'), 8 | cert: fs.readFileSync('/etc/letsencrypt/live/meusite.com.br/fullchain.pem'), 9 | ca: fs.readFileSync('/sites/CA/bundle.crt'), 10 | requestCert: true, 11 | rejectUnauthorized: false 12 | } 13 | 14 | app.use(function (req, res, next) { 15 | res.writeHead(200) 16 | res.end(req.socket.getPeerCertificate().subject.CN + "\n") 17 | // console.log(req.socket.getPeerCertificate().subject.CN) 18 | next() 19 | }) 20 | 21 | var listener = https.createServer(options, app).listen(433, function () { 22 | console.log('Express HTTPS server listening on port ' + listener.address().port); 23 | }) 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 c0h1b4 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Autenticação-ICP-Brasil 2 | Instruções para autenticar um token/certificado A1/A3 no site, apresentando o e-CPF ou e-CNPJ 3 | 4 | Instruções para os seguintes cenários: 5 | 6 | 1. **Utilizando o servidor NGINX** como autenticador para o certificado, e obtendo os dados de e-CPF e/ou e-CNPJ em aplicativos PHP ou Node.JS 7 | 2. **Utilizando o servidor Node.JS** como autenticador para o certificado através do módulo Express para autenticar o certificado e obter os dados de e-CPF e/ou e-CNPJ para utilização no Node.JS 8 | 3. **Utilizando um servidor APACHE** como autenticador para o certificado (TODO) 9 | 4. **Utilizando o API GATEWAY do AWS** no caso de aplicações serverless (AWS Lambda) (TODO) 10 | 11 | Na pasta CA, temos o bundle completo de chaves para autenticação, obtido através do gist https://gist.github.com/skarllot/9663935 12 | 13 | Os exemplos estão com documentação incluída nos próprios arquivos. 14 | 15 | ~~Obs1: 16 | Tanto na opção de NGINX quanto na do NodeJS, a solicitação de certificado não funciona com o FireFox. Ele pergunta a senha do token mas não solicita o certificado do token. No Edge ele pergunta qual certificado do token será utilizado mas depois não lê o certificado. No Chrome, Internet Explorer e Opera, funcionou perfeito.~~ Com o novo bundle de certificados, agora funciona em todos os navegadores. O novo bundle foi criado através do gist do skarllot/make-icpbrasil-bundle.sh (https://gist.github.com/skarllot/9663935) 17 | 18 | Obs2: 19 | Os dados do CPF ou CNPJ estão na variável CN, no formato XXX:NNN, onde o XXX é o nome do titular do CPF ou razão social da empresa e o NNN é o numero do CPF ou CNPJ. Então o ideal é usar um comando split com o caracter ':' como divisor e você terá um array onde o item 0 é o nome/razão social e o item 1 é o número do cpf/cnpj. Remova os 3 primeiros caracteres do item 0, pois estes tem sempre o 'CN=' -------------------------------------------------------------------------------- /NGINX/site.nginx: -------------------------------------------------------------------------------- 1 | # Instrução para redirecionar acessos pela porta 80 (HTTP) para a porta HTTPS (443) 2 | server { 3 | listen 80; 4 | server_name meusite.com.br; 5 | return 301 https://$server_name$request_uri; 6 | } 7 | 8 | # Neste caso, estou utilizando chaves SSL do letsencrypt que ficam normalmente armazenadas no diretório /etc/letsencrypt/live/ 9 | 10 | server { 11 | listen 443 ssl http2; 12 | server_name meusite.com.br; 13 | ssl on; 14 | ssl_certificate /etc/letsencrypt/live/meusite.com.br/fullchain.pem; 15 | ssl_certificate_key /etc/letsencrypt/live/meusite.com.br/privkey.pem; 16 | ssl_session_cache shared:SSL:20m; 17 | ssl_session_timeout 180m; 18 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 19 | ssl_prefer_server_ciphers on; 20 | ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; 21 | ssl_dhparam /sites/keys/dhparam.pem; 22 | 23 | #A mágica acontece aqui: 24 | #no próximo bloco, fazemos as instruções paraque o NGINX solicite o certificado do cliente. 25 | #existem diversas opções para o ssl_verify_client, mas as 2 que você poderá utilizar são: 26 | # optional -> verifica se tem o certificado. Se não tiver, continua com o site funcionando sem apresentar tela de erro. Você poderá verificar na página PHP ou JS (nodejs) se o certificado foi validado e quais os dados do certificado e apresentar uma mensagem ao usuário informando se não foi possível validar o certificado. 27 | # on -> força o usuário a utilizar o certificado, apresentado a página de erro 400 Bad Request, com o texto 'No required SSL certificate was sent'. Você poderá fazer uma página custom mas acho que a opção 'optional' dá uma melhor experiência ao usuário. 28 | 29 | ssl_client_certificate /sites/CA/bundle.crt; 30 | ssl_verify_client optional; 31 | ssl_verify_depth 10; 32 | 33 | #localização dos arquivos do site + página inicial (index.php) 34 | root /sites/meusite.com.br/public; 35 | index index.php index.html index.htm; 36 | charset utf-8; 37 | 38 | #local onde é gravado os logs de erros 39 | error_log /var/log/nginx/meusite.com.br.error; 40 | 41 | #o meu NGINX tem o compactador brotli incluído na compilação custom. Se o seu NGINX não tem o brotli, remova a linha abaixo 42 | brotli_types text/plain text/css application/javascript application/json image/svg+xml application/xml+rss; 43 | 44 | #linha para processamento de arquivos PHP de sites tipo Laravel (que são o que estou utilizando no momento) 45 | location / { 46 | try_files $uri $uri/ /index.php$is_args$args; 47 | } 48 | 49 | error_page 404 /index.php; 50 | 51 | #as páginas PHP são processadas pelo PHP ou HipHop através da porta 9000. Se estiver utilizando o método de socket, troque o fastcgi_pass 52 | location ~ \.(php)$ { 53 | fastcgi_param HTTP_ACCEPT_ENCODING ""; 54 | fastcgi_keep_conn on; 55 | # fastcgi_pass unix:/var/run/php7.0-fpm.sock; 56 | fastcgi_pass 127.0.0.1:9000; 57 | fastcgi_index index.php; 58 | # aqui passamos os dados do certificado para o interpretador PHP 59 | fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn if_not_empty; 60 | fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify if_not_empty; 61 | 62 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 63 | include fastcgi_params; 64 | } 65 | 66 | #se estiver utilizando um servidor nodejs, na url 'meusite.com.br/nodejs', aqui está a configuração: 67 | location /nodejs { 68 | proxy_set_header X-Real-IP $remote_addr; 69 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 70 | proxy_set_header Host $http_host; 71 | proxy_set_header X-NginX-Proxy true; 72 | proxy_set_header VERIFIED $ssl_client_verify; 73 | proxy_set_header DN $ssl_client_s_dn; 74 | 75 | proxy_pass http://127.0.0.1:3000; 76 | proxy_redirect off; 77 | } 78 | } 79 | 80 | 81 | 82 | 83 | 84 | 85 | --------------------------------------------------------------------------------