Статьи

Генерация ключей на основе браузера и взаимодействие с хранилищем ключей / сертификатов браузера

Представьте себе следующий сценарий:
Вы должны получить ключ (в асимметричном случае открытый ключ пользователя ) от пользователя, посещающего ваш сайт, и хотите, чтобы браузер запомнил личную часть, не мешая пользователю длительными процедурами импорта. Если честно, на практике вы даже не хотите, чтобы пользователь имел дело с криптографическими деталями — деталями, которые многие пользователи не могут знать и ничего не знают о них правильно. Он должен просто работать, и в лучшем случае пользователь даже не должен замечать, что криптография творит чудеса!
Представьте себе, например, центр сертификации всего предприятия, где сотрудники могут подать заявку на сертификаты или обновить существующие сертификаты, необходимые для входа в корпоративную систему веб-почты. Это не является частью основных задач сотрудника, поэтому процесс должен быть простым, быстрым и без необходимости читать какие-либо

Документация. Слава Богу — или в данном случае Netscape — HTML поставляется, поскольку HTML 5 даже не зависит от браузера, как часть официальных стандартов, с тегом, предназначенным для генерации ключа: <KeyGen />. Короче говоря, тег может заставить браузер пользователя создать асимметричную пару ключей, подписать соответствующий открытый ключ и заданный сервером запрос и, наконец, отправить его обратно на сервер (точнее, в местоположение, определенное в действии формы). атрибут). Закрытый ключ автоматически шифруется и сохраняется в хранилище ключей браузера. Формат, используемый для инкапсуляции открытого ключа, вызова и подписи, называется SPKAC . Если сервер отвечает сертификатом X.509, сертификат напрямую связан с закрытым ключом и хранится в хранилище сертификатов браузера.

В результате браузер теперь обладает предоставленным сервером (возможно, недавно созданным) сертификатом и соответствующим закрытым ключом. И все это одним простым нажатием на кнопку отправки. (Да, возможно, пользователь должен также добавить некоторые детали в поля формы …) А вот как это сделать в Java. Для простоты мы будем использовать быстрое и грязное решение на стороне сервера, напрямую регистрируясь как сервлет .

Сначала мы начнем с первоначального веб-сайта, который представляет форму, в которую необходимо ввести некоторые сведения о заявителе сертификата. Обратите внимание, что эти поля формы НЕ защищены подписью с вновь созданным закрытым ключом! Эта подпись защищает только открытый ключ и проблему, которая в данном случае — для простоты — жестко запрограммирована, но должна быть новым значением, выбранным сервером в сценарии реального мира. Следовательно, важно защитить как доставку веб-сайта, включая форму (она содержит критические значения безопасности, вызов, действие формы,… которое должно быть защищено целостностью), так и передачу данных обратно на сервер. Еще раз, если вам не удастся защитить связь и обеспечить хотя бы целостность цели безопасности, злоумышленник может нарушить всю вашу концепцию безопасности !

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<form action="CreateCertificate" method="POST">
<table>
       <tbody>
                <tr>
                    <td>Country name</td>
                    <td>C</td>
                    <td><input name="c" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Common name</td>
                    <td>CN</td>
                    <td><input name="cn" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Organizational unit</td>
                    <td>OU</td>
                    <td><input name="ou" type="text" value="" /></td>
                </tr>
                <tr>
                    <td>Organization</td>
                    <td>O</td>
                    <td><input name="o" type="text" value="" /></td>
                </tr>
                <tr>
                    <td></td>
                    <td><keygen challenge="replaceMe" keyparams="2048" keytype="rsa"
                      name="newSPKAC"></keygen></td>
                    <td><input type="submit" value="Generate!" /></td>
                </tr>
       </tbody>
</table>
</form>

На стороне сервера необходимо зарегистрировать класс обработки для цели действия формы. Это делается в вашем файле конфигурации web.xml.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<web-app version="3.0" xmlns:xsi="..." xmlns="..." xsi:schemalocation="...">
    <servlet>
        <servlet-name>CreateCertificate</servlet-name>
        <servlet-class>
            com.blogspot.armoredbarista.examples.certificates.CreateCertificate
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CreateCertificate</servlet-name>
        <url-pattern>/CreateCertificate</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

Это приводит к тому, что любой вызов пути / CreateCertificate обрабатывается классом CreateCertificate. Класс CreateCertificate, в свою очередь, делает то, что мы ожидаем от имени: он создает сертификат, включающий полученный открытый ключ и данные запрашивающей стороны. Открытый ключ и вызов включены в структуру SPKAC, созданную тегом KeyGen (который в этом случае идентифицируется именем newSPKAC).

01
02
03
04
05
06
07
08
09
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
public class CreateCertificate extends HttpServlet {
    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {
 
        OutputStream out = response.getOutputStream();
        byte[] content = "An error occured".getBytes("UTF-8");
        try {
            String c = request.getParameter("c");
            String cn = request.getParameter("cn");
            String o = request.getParameter("o");
            String ou = request.getParameter("ou");
            String newSPKAC = request.getParameter("newSPKAC");
 
            X509Certificate cert = createCertificate(c, cn, ou, o, newSPKAC);
            content = cert.getEncoded();
 
            response.setContentType("application/x-x509-user-cert");
            response.setHeader("Pragma", "No-Cache");
            response.setDateHeader("EXPIRES", -1);
        } catch (...) {
          // error processing
        } finally {
            out.write(content);
            out.flush();
            out.close();
        }
    }
 
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
 
    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(final HttpServletRequest request,
            final HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

ContentType, используемый для ответа, в этом случае application / x-x509-user-cert.

И это все. После того, как пользователь введет свои данные и нажмет на кнопку, он должен найти новый сертификат в хранилище сертификатов браузера:

И последнее слово о демонтаже SPKAC: BouncyCastle может помочь вам бороться со зверями ASN.1 и DER !