<!-- Generated from prerendered index.html. HTML SHA-256: 05f90a8345dcd71aeb6525c36f71f515de66e6ba7a6bfbd6ffe3fdb07a1509be -->

# 07 · Signature avancée : construire une signature PAdES B-B

> Section autonome du guide [eIDAS 2, échange par échange](https://signature.codethelaw.eu/).

En production

Formats normalisés et implémentés par tous les outils de signature européens : ETSI EN 319 142-1 (PAdES), CMS (RFC 5652), ESS (RFC 5035). Algorithmes : ETSI TS 119 312 V2.1.1.

À format PAdES équivalent, une signature qualifiée est une signature avancée qui repose en outre sur un certificat qualifié et qui est créée au moyen d'un dispositif de création de signature qualifié (QSCD). Elle reste soumise aux exigences de l'article 26 : lien univoque avec le signataire, capacité à l'identifier, création à l'aide de données que le signataire peut utiliser sous son contrôle exclusif, et détection de toute modification ultérieure des données signées. Cette section construit la structure, octet par octet, avec un jeton personnel.

## 7.1 Réserver la place de la signature

Application de signature → Application de signature · Préparer le PDF

### Entrée

PDF d'origine.

**TEXTE**

```text
contrat-2026-118.pdf (révision 1)
```

### Traitement

1.  Ajouter une mise à jour incrémentale contenant un champ de signature et un dictionnaire de signature.
2.  Réserver /Contents : 8 192 octets à zéro, soit 16 384 chiffres hexadécimaux entre chevrons.
3.  Calculer /ByteRange : tout le fichier sauf la valeur de /Contents.

### Sortie

Dictionnaire de signature.

**PDF · PAdES**

```text
12 0 obj
<< /Type /Sig
   /Filter /Adobe.PPKLite
   /SubFilter /ETSI.CAdES.detached
   /ByteRange [0 840 17226 1530]
   /Contents <0000000000…0000>          % 16 384 chiffres hex réservés
   /M (D:20261003101500+02'00')        % heure revendiquée : dans le PDF, pas dans le CMS
   /Name (Camille DUPONT)
   /Reason (Accord sur le contrat 2026-118)
>>
endobj
% octets 840 à 17225 : '<' + 16 384 hex + '>'  (17226 - 840 = 16 386)
```

**Suite :** Le condensat porte sur les deux plages d'octets : \[0, 840\[ et \[17226, 18756\[.

## 7.2 Calculer le condensat du document

Application de signature → Application de signature · messageDigest

### Entrée

Les deux plages /ByteRange.

**TEXTE**

```text
octets [0 .. 839]  ||  octets [17226 .. 18755]
```

### Traitement

1.  SHA-256 sur la concaténation des deux plages.
2.  C'est ce condensat qui lie la signature au document ; tout octet modifié hors /Contents change la valeur.

### Sortie

**TEXTE**

```text
messageDigest = SHA-256(plages) = <32 octets>
```

**Suite :** Le condensat est placé dans les attributs signés.

## 7.3 Construire les attributs signés

Application de signature → Application de signature · signedAttrs

### Entrée

Condensat et certificat du signataire.

**TEXTE**

```text
messageDigest
certificat du signataire (DER)
```

### Traitement

1.  contentType = id-data.
2.  messageDigest = condensat de l'étape précédente.
3.  signingCertificateV2 = SHA-256 du certificat du signataire : empêche de substituer un autre certificat portant la même clé.
4.  Pas d'attribut signingTime : en PAdES, l'heure revendiquée est dans /M.
5.  Encodage DER de l'ensemble avec l'étiquette SET (0x31) : c'est ce bloc qui est signé, pas le document.

### Sortie

Attributs signés (notation ASN.1).

**ASN.1**

```text
SET {
  SEQUENCE {                                  -- contentType
    OBJECT IDENTIFIER 1.2.840.113549.1.9.3
    SET { OBJECT IDENTIFIER 1.2.840.113549.1.7.1 }        -- id-data
  }
  SEQUENCE {                                  -- messageDigest
    OBJECT IDENTIFIER 1.2.840.113549.1.9.4
    SET { OCTET STRING <SHA-256 des plages ByteRange> }
  }
  SEQUENCE {                                  -- signingCertificateV2 (RFC 5035)
    OBJECT IDENTIFIER 1.2.840.113549.1.9.16.2.47
    SET { SEQUENCE { SEQUENCE { SEQUENCE {    -- SigningCertificateV2 / certs / ESSCertIDv2
      OCTET STRING <SHA-256 du certificat>    -- hashAlgorithm omis : SHA-256 par défaut
      SEQUENCE { <issuer>, <serialNumber> }   -- IssuerSerial
    } } } }
  }
}
```

**Suite :** Le condensat SHA-256 de ce bloc DER est envoyé au jeton pour signature.

## 7.4 Activer la clé avec le PIN

Signataire → Jeton ou carte · PIN

### Entrée

Interface PKCS#11 côté poste.

**TEXTE**

```text
C_OpenSession(slot, CKF_SERIAL_SESSION, …, &hSession)
C_Login(hSession, CKU_USER, "<PIN>", len)
```

### Traitement

1.  Le PIN est vérifié par le jeton lui-même ; après un petit nombre d'échecs, le jeton se bloque.
2.  La clé privée n'est utilisable que dans cette session authentifiée.

### Sortie

**TEXTE**

```text
Session authentifiée : CKR_OK
```

**Suite :** Le logiciel demande la signature du condensat.

## 7.5 Signer le condensat dans le jeton

Application de signature → Jeton ou carte · C\_Sign

### Entrée

Appel PKCS#11.

**TEXTE**

```text
h = SHA-256(DER(signedAttrs))                       -- 32 octets, calculés sur le poste
C_SignInit(hSession, { CKM_ECDSA }, hPrivateKey)
C_Sign(hSession, h, 32, sig, &sigLen)
```

### Traitement

1.  Le jeton calcule une signature ECDSA P-256 sur h avec la clé privée qui ne le quitte jamais.
2.  PKCS#11 renvoie la signature brute r || s (64 octets).
3.  Le logiciel la réencode en ECDSA-Sig-Value DER pour CMS.

### Sortie

**ASN.1**

```text
r || s  (64 octets)  =>  SEQUENCE { INTEGER r, INTEGER s }   -- environ 70 à 72 octets en DER
```

**Suite :** La signature est intégrée à la structure CMS.

## 7.6 Assembler le CMS et l'insérer dans le PDF

Application de signature → Application de signature · CMS → /Contents

### Entrée

Signature, attributs signés, certificats.

**TEXTE**

```text
signedAttrs, signature DER, certificat du signataire, certificat de l'AC
```

### Traitement

1.  Construire le SignedData détaché (le document n'est pas copié dans le CMS).
2.  Encoder en DER, convertir en hexadécimal et écrire dans la zone /Contents réservée, sans changer la longueur du fichier.

### Sortie

Structure CMS (RFC 5652).

**CMS · RFC 5652**

```text
ContentInfo {
  contentType 1.2.840.113549.1.7.2                       -- signedData
  content [0] SignedData {
    version 1
    digestAlgorithms { 2.16.840.1.101.3.4.2.1 }          -- sha256
    encapContentInfo { eContentType 1.2.840.113549.1.7.1 }   -- détaché : pas d'eContent
    certificates [0] { <certificat du signataire>, <certificat de l'AC> }
    signerInfos {
      SignerInfo {
        version 1
        sid issuerAndSerialNumber { <issuer>, <serialNumber> }
        digestAlgorithm 2.16.840.1.101.3.4.2.1
        signedAttrs [0] { contentType, messageDigest, signingCertificateV2 }
        signatureAlgorithm 1.2.840.10045.4.3.2           -- ecdsa-with-SHA256
        signature OCTET STRING <ECDSA-Sig-Value DER>
        -- unsignedAttrs : vide au niveau B-B (le niveau B-T y ajoutera l'horodatage)
      }
    }
  }
}
```

**BASE LÉGALE.** Avancée au sens de l'article 26 si le certificat identifie le signataire et si la clé est sous son contrôle exclusif. Qualifiée si, en plus, le certificat est qualifié et le jeton est un QSCD notifié (sections 8 et 10).

**Suite :** Le fichier est une signature PAdES B-B. Sa qualification dépend du certificat et du dispositif, pas de cette structure.

## Sources

-   [ETSI TS 119 312 V2.1.1 (2026-06), suites cryptographiques](https://www.etsi.org/deliver/etsi_ts/119300_119399/119312/02.01.01_60/ts_119312v020101p.pdf)
-   ETSI EN 319 142-1, PAdES (référencée par TS 119 312)
-   [RFC 5652, Cryptographic Message Syntax](https://www.rfc-editor.org/info/rfc5652)
-   [RFC 5035, ESS signingCertificateV2](https://www.rfc-editor.org/info/rfc5035)
