Aller au contenu

openssl : Liaison OpenSSL basée sur FFI pour nginx-module-lua

Installation

Si vous n'avez pas configuré l'abonnement au dépôt RPM, inscrivez-vous. Vous pouvez ensuite procéder aux étapes suivantes.

CentOS/RHEL 7 ou Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-openssl

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-openssl

Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.

Ce document décrit lua-resty-openssl v1.9.0 publié le 14 août 2026.


Liaison OpenSSL basée sur FFI pour LuaJIT, prenant en charge OpenSSL 3, 4 et la série 1.1.1.

La prise en charge d'OpenSSL 1.1.0, 1.0.2 et BoringSSL a été abandonnée, mais reste disponible dans la branche 0.x.

Build Status luarocks opm

Description

lua-resty-openssl est une bibliothèque de liaison OpenSSL basée sur FFI, qui prend actuellement en charge OpenSSL 3.x, 4.x et la série 1.1.1.

Synopsis

Cette bibliothèque est fortement inspirée par luaossl et utilise une convention de nommage plus proche de l'API OpenSSL d'origine. Par exemple, une fonction appelée X509_set_pubkey dans l'API C d'OpenSSL est exposée comme resty.openssl.x509:set_pubkey. Les CamelCases sont remplacées par des underscore_cases, par exemple X509_set_serialNumber devient resty.openssl.x509:set_serial_number. Une autre différence par rapport à luaossl est que les erreurs ne sont jamais levées en utilisant error() mais sont plutôt retournées comme dernier paramètre.

Chaque table Lua retournée par new() contient un objet cdata ctx. Les utilisateurs ne sont pas censés définir manuellement ffi.gc ou appeler le destructeur correspondant de la structure ctx (comme les fonctions *_free).

resty.openssl

Ce module méta fournit une vérification de cohérence de version par rapport à la bibliothèque OpenSSL liée.

openssl.load_library

syntaxe : name, err = openssl.load_library()

Tente de charger les bibliothèques partagées OpenSSL. Cette fonction essaie plusieurs modèles de noms de bibliothèque connus et retourne le nom de la bibliothèque crypto lorsqu'elle est chargée avec succès, ou une erreur le cas échéant.

Lorsqu'elle est exécutée dans le CLI resty ou OpenResty avec SSL activé, l'appel de cette fonction n'est pas nécessaire.

openssl.load_modules

syntaxe : openssl.load_modules()

Charge tous les sous-modules disponibles dans le module courant :

  bn = require("resty.openssl.bn"),
  cipher = require("resty.openssl.cipher"),
  digest = require("resty.openssl.digest"),
  hmac = require("resty.openssl.hmac"),
  kdf = require("resty.openssl.kdf"),
  pkey = require("resty.openssl.pkey"),
  objects = require("resty.openssl.objects"),
  rand = require("resty.openssl.rand"),
  version = require("resty.openssl.version"),
  x509 = require("resty.openssl.x509"),
  altname = require("resty.openssl.x509.altname"),
  chain = require("resty.openssl.x509.chain"),
  csr = require("resty.openssl.x509.csr"),
  crl = require("resty.openssl.x509.crl"),
  extension = require("resty.openssl.x509.extension"),
  extensions = require("resty.openssl.x509.extensions"),
  name = require("resty.openssl.x509.name"),
  store = require("resty.openssl.x509.store"),
  ssl = require("resty.openssl.ssl"),
  ssl_ctx = require("resty.openssl.ssl_ctx"),

À partir d'OpenSSL 3.0, provider, mac et ctx sont également disponibles.

openssl.luaossl_compat

syntaxe : openssl.luaossl_compat()

Fournit une API de type luaossl qui utilise la dénomination camelCase ; les utilisateurs peuvent s'attendre à un remplacement direct.

Par exemple, pkey:get_parameters est mappé à pkey:getParameters.

Notez que toute l'API luaossl n'a pas été implémentée, veuillez consulter le readme pour la source de vérité.

openssl.get_fips_mode

syntaxe : enabled = openssl.get_fips_mode()

Retourne un booléen indiquant si le mode FIPS est activé.

openssl.set_fips_mode

syntaxe : ok, err = openssl.set_fips_mode(enabled)

Active ou désactive le mode FIPS.

lua-resty-openssl prend en charge les modes suivants :

Série OpenSSL 1.0.2 avec module fips 2.0

Compiler le module conformément à la politique de sécurité,

Fournisseur FIPS OpenSSL 3

Se référer à https://wiki.openssl.org/index.php/OpenSSL_3.0 Section 7 Compiler le fournisseur selon le guide, installer le fipsmodule.cnf qui correspond au hachage du fournisseur FIPS fips.so.

À partir d'OpenSSL 3.0, cette fonction active et désactive également les propriétés par défaut pour les fonctions EVP. Lorsqu'il est activé, toutes les applications utilisant l'API EVP_* seront redirigées vers des implémentations conformes FIPS et n'auront pas accès aux algorithmes non conformes FIPS.

L'appel de cette fonction équivaut à charger le fournisseur fips et à appeler openssl.set_default_properties("fips=yes").

Si le fournisseur FIPS est chargé mais que les propriétés par défaut ne sont pas définies, utilisez ce qui suit pour récupérer explicitement l'implémentation FIPS.

local provider = require "resty.openssl.provider"
assert(provider.load("fips"))
local cipher = require "resty.openssl.cipher"
local c = assert(cipher.new("aes256"))
print(c:get_provider_name()) -- affiche "default"
local c = assert(cipher.new("aes256", "fips=yes"))
print(c:get_provider_name()) -- affiche "fips"

openssl.get_fips_version_text

syntaxe : text, err = openssl.get_fips_version_text()

Retourne le texte de version du module FIPS, disponible sur OpenSSL 3.0 ou version ultérieure.

openssl.set_default_properties

syntaxe : ok, err = openssl.set_default_properties(props)

Définit les propriétés par défaut pour toutes les futures récupérations d'algorithmes EVP, implicites et explicites. Voir "ALGORITHM FETCHING" dans crypto(7) pour des informations sur la récupération implicite et explicite.

openssl.list_cipher_algorithms

syntaxe : ret = openssl.list_cipher_algorithms(hide_provider?)

Retourne les algorithmes de chiffrement disponibles dans un tableau. Définissez hide_provider sur true pour masquer le nom du fournisseur du résultat.

openssl.list_digest_algorithms

syntaxe : ret = openssl.list_digest_algorithms(hide_provider?)

Retourne les algorithmes de digest disponibles dans un tableau. Définissez hide_provider sur true pour masquer le nom du fournisseur du résultat.

openssl.list_mac_algorithms

syntaxe : ret = openssl.list_mac_algorithms(hide_provider?)

Retourne les algorithmes MAC disponibles dans un tableau. Définissez hide_provider sur true pour masquer le nom du fournisseur du résultat.

openssl.list_kdf_algorithms

syntaxe : ret = openssl.list_kdf_algorithms(hide_provider?)

Retourne les algorithmes KDF disponibles dans un tableau. Définissez hide_provider sur true pour masquer le nom du fournisseur du résultat.

openssl.list_ssl_ciphers

syntaxe : cipher_string, err = openssl.list_ssl_ciphers(cipher_list?, ciphersuites?, protocol?)

Retourne les chiffrements SSL par défaut sous forme de chaîne. cipher_list (avant TLSv1.3) et ciphersuites (TLSv1.3) peuvent être utilisés pour développer les paramètres de chiffrement correspondant au protocol. OpenSSL 4.x rejette "SSLv3" car la prise en charge de SSLv3 a été supprimée.

openssl.list_ssl_ciphers()
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA")
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA", nil, "TLSv1.2")
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA", "TLS_CHACHA20_POLY1305_SHA256", "TLSv1.3")

resty.openssl.ctx

Un module pour fournir les changements de contexte OSSL_LIB_CTX.

OSSL_LIB_CTX est un type de contexte de bibliothèque OpenSSL interne. Les applications peuvent allouer le leur, mais peuvent également utiliser NULL pour utiliser un contexte par défaut avec des fonctions qui prennent un argument OSSL_LIB_CTX.

Voir OSSL_LIB_CTX.3 pour une lecture plus approfondie.

Le contexte affecte actuellement les modules suivants :

Ce module est disponible sur OpenSSL 3.0 ou version ultérieure.

ctx.new

syntaxe : ok, err = ctx.new(request_context_only?, conf_file?)

Crée un nouveau contexte et l'utilise comme contexte par défaut pour ce module. Lorsque request_context_only est défini sur true, le contexte n'est utilisé que dans le contexte de la requête courante. conf_file peut éventuellement spécifier un fichier de configuration OpenSSL pour créer le contexte.

Le contexte créé est automatiquement libéré avec son cycle de vie donné.

-- initialise une instance de chiffrement AES à partir de l'implémentation du fournisseur donné uniquement
-- pour la requête courante, sans interférer avec d'autres parties du code
-- ou les futures requêtes utilisant le même algorithme.
assert(require("resty.openssl.ctx").new(true))
local p = assert(require("resty.openssl.provider").load("myprovider"))
local c = require("resty.openssl.cipher").new("aes256")
print(c:encrypt(string.rep("0", 32), string.rep("0", 16), "🦢"))
-- pas besoin de libérer le fournisseur et le ctx, ils sont libérés automatiquement par le GC

ctx.free

syntaxe : ctx.free(request_context_only?)

Libère le contexte qui a été précédemment créé par ctx.new.

resty.openssl.err

Un module pour fournir des messages d'erreur.

err.format_error

syntaxe : msg = err.format_error(ctx_msg?, return_code?, all_errors?)

syntaxe : msg = err.format_all_errors(ctx_msg?, return_code?)

Retourne le dernier message d'erreur du dernier code d'erreur. Les erreurs sont formatées comme suit :

[ctx_msg] : https://github.com/fffonion/lua-resty-openssl/blob/1.9.0/code: [return_code]: error:[error code]:[library name]:[func name]:[reason string]:[file name]:[line number]:

Pour les versions d'OpenSSL antérieures à 3.0, les erreurs sont formatées comme suit :

[ctx_msg] : https://github.com/fffonion/lua-resty-openssl/blob/1.9.0/code: [return_code]: [file name]:[line number]:error:[error code]:[library name]:[func name]:[reason string]:

Si all_errors est défini sur true, toutes les erreurs, pas seulement la plus récente, seront retournées dans une seule chaîne. Toutes les erreurs levées en interne par cette bibliothèque ne lèvent que la dernière erreur.

Par exemple :

local f = io.open("t/fixtures/ec_key_encrypted.pem"):read("*a")
local privkey, err = require("resty.openssl.pkey").new(f, {
    format = "PEM",
    type = "pr",
    passphrase = "wrongpasswrod",
})
ngx.say(err)
-- pkey.new:load_key: error:4800065:PEM routines:PEM_do_header:bad decrypt:crypto/pem/pem_lib.c:467:

err.get_last_error_code

syntaxe : code = err.get_last_error_code()

Retourne le dernier code d'erreur.

err.get_lib_error_string

syntaxe : lib_error_message = err.get_lib_error_string(code?)

Retourne le nom de la bibliothèque du dernier code d'erreur sous forme de chaîne. Si code est défini, retourne le nom de la bibliothèque correspondant au code d'erreur fourni à la place.

err.get_reason_error_string

syntaxe : reason_error_message = err.get_reason_error_string(code?)

Retourne la raison du dernier code d'erreur sous forme de chaîne. Si code est défini, retourne la raison correspondant au code d'erreur fourni à la place.

resty.openssl.version

Un module pour fournir des informations de version.

resty.openssl.provider

Module pour interagir avec les fournisseurs. Ce module ne fonctionne que sur OpenSSL 3.0 ou version ultérieure.

provider.load

syntaxe : pro, err = provider.load(name, try?)

Charge le fournisseur avec name. Si try est défini sur true, OpenSSL ne désactivera pas les fournisseurs de repli si le fournisseur ne peut pas être chargé et initialisé. Si le fournisseur se charge avec succès, cependant, les fournisseurs de repli sont désactivés.

Par défaut, cette fonction charge le fournisseur dans le contexte par défaut, ce qui signifie qu'elle affectera d'autres applications dans le même processus utilisant également le contexte par défaut. Si un tel comportement n'est pas souhaité, envisagez d'utiliser ctx pour charger le fournisseur uniquement dans une portée limitée.

provider.istype

syntaxe : ok = pkey.provider(table)

Retourne true si la table est une instance de provider. Retourne false sinon.

provider.is_available

syntaxe : ok, err = provider.is_available(name)

Vérifie si un fournisseur nommé est disponible pour utilisation.

provider.set_default_search_path

syntaxe : ok, err = provider.set_default_search_path(name)

Spécifie le chemin de recherche par défaut à utiliser pour rechercher les fournisseurs.

provider:unload

syntaxe : ok, err = pro:unload(name)

Décharge un fournisseur précédemment chargé par provider.load.

provider:self_test

syntaxe : ok, err = pro:self_test(name)

Exécute les auto-tests d'un fournisseur à la demande. Si les auto-tests échouent, le fournisseur ne pourra plus fournir de services et d'algorithmes supplémentaires.

provider:get_params

syntaxe : ok, err = pro:get_params(key1, key2?...)

Retourne une ou plusieurs valeurs de paramètres du fournisseur.

local pro = require "resty.openssl.provider"

local p = pro.load("default")

local name = assert(p:get_params("name"))
print(name)
-- affiche "OpenSSL Default Provider"

local result = assert(p:get_params("name", "version", "buildinfo", "status"))
print(require("cjson").encode(result))
-- affiche les métadonnées du fournisseur ; la version et buildinfo varient selon la version d'OpenSSL

resty.openssl.pkey

Module pour interagir avec les clés privées et publiques (EVP_PKEY).

Chaque type de clé peut ne supporter qu'une partie des opérations :

Type de clé Charger une clé existante Génération de clé Chiffrement/Déchiffrement Signature/Vérification Échange de clés Encapsulation/Décapsulation
RSA O O O O O (RSASVE, OpenSSL 3.5+)
DH O O O
EC O O O (ECDSA) O (ECDH) O (DHKEM, OpenSSL 3.5+)
Ed25519 O O O (PureEdDSA)
X25519 O O O (ECDH) O (DHKEM, OpenSSL 3.5+)
Ed448 O O O (PureEdDSA)
X448 O O O (ECDH) O (DHKEM, OpenSSL 3.5+)
ML-DSA (OpenSSL 3.5+) O O O
SLH-DSA (OpenSSL 3.5+) O O O
ML-KEM (OpenSSL 3.5+) O O O
ML-KEM hybride TLS (OpenSSL 3.5+) Dépend du fournisseur O O

La prise en charge directe du chiffrement et du déchiffrement pour EC et ECX n'existe pas, mais des processus comme ECIES sont possibles avec pkey:derive, kdf et cipher

pkey.new

Charger une clé existante

syntaxe : pk, err = pkey.new(string, opts?)

Prend en charge le chargement d'une clé privée ou publique au format PEM, DER ou JWK passée comme premier argument string.

Le deuxième paramètre opts accepte une table optionnelle pour contraindre le comportement de chargement de clé.

  • opts.format : définir explicitement sur "PEM", "DER", "JWK" pour charger un format spécifique ou sur "*" pour la détection automatique
  • opts.type : définir explicitement sur "pr" pour une clé privée, "pu" pour une clé publique ; définir sur "*" pour la détection automatique

Lors du chargement d'une clé RSA encodée en PEM, il peut s'agir soit d'une SubjectPublicKeyInfo/PrivateKeyInfo encodée en PKCS#8, soit d'une RSAPublicKey/RSAPrivateKey encodée en PKCS#1.

Lors du chargement d'une clé encodée en PEM chiffrée, la passphrase pour la déchiffrer peut être définie dans opts.passphrase ou opts.passphrase_cb :

pkey.new(pem_or_der_text, {
  format = "*", -- choix de "PEM", "DER", "JWK" ou "*" pour la détection automatique
  type = "*", -- choix de "pr" pour une clé privée, "pu" pour une clé publique et "*" pour la détection automatique
  passphrase = "secret password", -- la passphrase de chiffrement PEM
  passphrase_cb = function()
    return "secret password"
  end, -- la fonction de rappel de passphrase de chiffrement PEM
}

Lors du chargement de JWK, il y a quelques mises en garde : - Assurez-vous que le texte JSON encodé est passé, il doit avoir été décodé en base64. - Contraindre opts.type pour les clés JWK nécessite OpenSSL 3.0 ou version ultérieure et lua-resty-openssl 1.6.0 ou version ultérieure. Avec OpenSSL 1.1.1 ou des versions plus anciennes de lua-resty-openssl, les paramètres du JSON fourni décideront si une clé privée ou publique est chargée ; spécifier type entraînera une erreur ; également, la partie clé publique pour les clés OKP (le paramètre x) n'est pas honorée et est dérivée de la partie clé privée (le paramètre d) si elle est spécifiée. - Seuls les types de clés RSA, P-256, P-384 et P-512 EC, Ed25519, X25519, Ed448 et X448 OKP sont pris en charge. - Les signatures et vérifications doivent utiliser l'option ecdsa_use_raw pour fonctionner avec les normes JWS pour les clés EC. Voir pkey:sign et pkey.verify pour plus de détails. - Lorsqu'il est exécuté en dehors d'OpenResty, il faut installer une bibliothèque JSON (cjson ou dkjson) et basexx.

Génération de clé

syntaxe : pk, err = pkey.new(config?)

Génère une nouvelle clé publique ou privée.

Pour générer une clé RSA, la table config peut avoir les champs bits et exp pour contrôler la génération de clé. Lorsque config est omis, cette fonction génère une clé RSA de 2048 bits avec un exponent de 65537, ce qui équivaut à :

local key, err = pkey.new({
  type = 'RSA',
  bits = 2048,
  exp = 65537
})

Pour générer une clé EC ou DH, veuillez vous référer à pkey.paramgen pour les valeurs possibles de la table config. Par exemple :

local key, err = pkey.new({
  type = 'EC',
  curve = 'prime256v1',
})

Sur OpenSSL 3.0 ou version ultérieure, tout type de clé implémenté par un fournisseur chargé peut être demandé par nom. Par exemple, OpenSSL 3.5 ou version ultérieure fournit des types de clés post-quantiques y compris :

local ml_dsa = assert(pkey.new({ type = "ML-DSA-44" }))
local ml_kem = assert(pkey.new({ type = "ML-KEM-768" }))
local slh_dsa = assert(pkey.new({ type = "SLH-DSA-SHA2-128s" }))

config.properties peut être utilisé pour sélectionner une implémentation de fournisseur pour ces types de clés natifs du fournisseur.

Il est également possible de passer des paramètres EC ou DH encodés en PEM à config.param pour la génération de clé :

local dhparam = pkey.paramgen({
  type = 'DH',
  group = 'dh_1024_160'
})
-- OU
-- local dhparam = io.read("dhparams.pem"):read("*a")

local key, err = pkey.new({
  type = 'DH',
  param = dhparam,
}) 

Il est également possible de passer des chaînes de contrôle pkeyopt brutes dans la table config comme utilisé dans le programme CLI genpkey. Voir openssl-genpkey(1) pour une liste d'options.

Par exemple :

pkey.new({
  type = 'RSA',
  bits = 2048,
  exp = 65537,
})
-- est identique à
pkey.new({
  type = 'RSA',
  exp = 65537,
  "rsa_keygen_bits:4096",
})

Composition de clé

syntaxe : pk, err = pkey.new(config?)

Compose une clé publique ou privée en utilisant des paramètres existants. Pour voir la liste des paramètres pour chaque clé, référez-vous à pkey:set_parameters.

Seuls type et params doivent exister dans la table config, toutes les autres clés seront ignorées.

local private_bn = require "resty.openssl.bn".new("7F48282CCA4C1A65D589C06DBE9C42AE50FBFFDF3A18CBB48498E1DE47F11BE1A3486CD8FA950D68F111970F922279D8", 16)
local p_384, err = assert(require("resty.openssl.pkey").new({
    type = "EC",
    params = {
        private = private_bn,
        group = "secp384r1",
    }
}))

pkey.istype

syntaxe : ok = pkey.istype(table)

Retourne true si la table est une instance de pkey. Retourne false sinon.

pkey.paramgen

syntaxe : pem_txt, err = pk.paramgen(config)

Génère des paramètres pour une clé EC ou DH et les sort sous forme de texte encodé PEM.

Pour une clé EC :

Paramètre Description
type "EC"
curve Courbes EC. Si omis, la valeur par défaut est "prime192v1". Pour voir la liste des courbes EC prises en charge, utilisez openssl ecparam -list_curves.

Pour une clé DH :

Paramètre Description
type "DH"
bits Génère un nouveau paramètre DH avec un nombre premier de longueur bits. Si omis, la valeur par défaut est 2048. À partir d'OpenSSL 3.0, seuls les bits égaux à 2048 sont autorisés.
group Utilise des groupes prédéfinis au lieu d'en générer un nouveau. bit sera ignoré si group est défini.

Les valeurs possibles pour group sont : - RFC7919 "ffdhe2048", "ffdhe3072", "ffdhe4096", "ffdhe6144", "ffdhe8192" - RFC5114 "dh_1024_160", "dh_2048_224", "dh_2048_256" - RFC3526 "modp_1536", "modp_2048", "modp_3072", "modp_4096", "modp_6144", "modp_8192"

local pem, err = pkey.paramgen({
  type = 'EC',
  curve = 'prime192v1',
})

local pem, err = pkey.paramgen({
  type = 'DH',
  group = 'ffdhe4096',
})

Il est également possible de passer des chaînes de contrôle pkeyopt brutes dans la table config comme utilisé dans le programme CLI genpkey. Voir openssl-genpkey(1) pour une liste d'options.

pkey:get_provider_name

syntaxe : name = pkey:get_provider_name()

Retourne le nom du fournisseur de pkey.

Cette fonction est disponible sur OpenSSL 3.0 ou version ultérieure.

pkey:gettable_params, pkey:settable_params, pkey:get_param, pkey:set_params

Interroge les paramètres définissables ou récupérables et définit ou récupère les paramètres. Voir Getter/setter générique de paramètres EVP.

pkey:get_parameters

syntaxe : parameters, err = pk:get_parameters()

Retourne une table contenant les parameters de l'instance pkey.

Pour les clés ECX et, séparément, les clés natives du fournisseur OpenSSL 3 telles que ML-KEM, ML-DSA, SLH-DSA et les clés hybrides ML-KEM TLS, la table expose les champs binaires public et private lorsque le fournisseur permet l'exportation de ces composants. Certains fournisseurs n'exportent intentionnellement pas de composant privé.

pkey:set_parameters

syntaxe : ok, err = pk:set_parameters(params)

Définit les paramètres de la pkey à partir d'une table params. Si le paramètre n'est pas défini dans la table params, il reste inchangé dans l'instance pkey.

Pour les clés ECX et, séparément, les clés natives du fournisseur OpenSSL 3, public et private contiennent les composants de clé binaires bruts. La définition de l'un ou l'autre composant remplace la clé immuable sous-jacente du fournisseur tout en préservant l'objet pkey.

local pk, err = require("resty.openssl.pkey").new()
local parameters, err = pk:get_parameters()
local e = parameters.e
ngx.say(e:to_number())
-- affiche 65537

local ok, err = pk:set_parameters({
  e = require("resty.openssl.bn").from_hex("100001")
})

local ok, err = pk:set_parameters(parameters)

Paramètres pour une clé RSA :

Paramètre Description Type
n module commun aux clés publique et privée bn
e exposant public bn
d exposant privé bn
p premier facteur de n bn
q deuxième facteur de n bn
dmp1 d mod (p - 1), exposant1 bn
dmq1 d mod (q - 1), exposant2 bn
iqmp (InverseQ)(q) = 1 mod p, coefficient bn

Paramètres pour une clé EC :

Paramètre Description Type
private clé privée bn
public clé publique bn
x coordonnée x de la clé publique bn
y coordonnée y de la clé publique bn
group le groupe de courbe nommé [NID] sous forme de nombre, lorsqu'il est passé dans set_parameters(), il est également possible d'utiliser la représentation textuelle. Ceci est différent de luaossl où une instance EC_GROUP est retournée.

Il n'est pas possible de définir x, y avec public en même temps car x et y sont essentiellement une autre représentation de public. De plus, actuellement il n'est possible de définir x et y qu'en même temps.

Paramètres pour une