Closed GnunuX closed 2 years ago
Same problem in isActorPrivateKeyValid function.
Hi,
PeerTube already uses latest pem
dependency. :thinking: You can check your version in /usr/share/peertube/node_modules/pem/package.json
Ok... I'm not very familiar with npm dependencies.
If I undestand correctly https://github.com/Dexus/pem/issues/313 , the package 1.14.5 had OpenSSL v3 support, but this package was broken. So pem version 1.14.6 is, in fact the version 1.14.4 (without OpenSSLv3 support).
You might want to modify the isActorPrivateKeyValid function to support OpenSSL v3 when pem does.
It seems we'll have to wait a proper pem
release containing openssl v3 support. Blocked by https://github.com/Dexus/pem/issues/316
Is there a workaround for this at the moment?
Here are my patches while waiting for an official solution:
--- peertube/dist/server/helpers/custom-validators/activitypub/actor.js.ori 2022-04-06 13:58:17.752681849 +0000
+++ peertube/dist/server/helpers/custom-validators/activitypub/actor.js 2022-04-06 13:58:22.268682531 +0000
@@ -43,8 +43,8 @@
function isActorPrivateKeyValid(privateKey) {
return (0, misc_1.exists)(privateKey) &&
typeof privateKey === 'string' &&
- privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') &&
- privateKey.includes('-----END RSA PRIVATE KEY-----') &&
+ privateKey.startsWith('-----BEGIN PRIVATE KEY-----') &&
+ privateKey.includes('-----END PRIVATE KEY-----') &&
validator_1.default.isLength(privateKey, constants_1.CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY);
}
exports.isActorPrivateKeyValid = isActorPrivateKeyValid;
--- peertube/node_modules/pem/lib/pem.js.ori 2022-04-06 13:59:36.232693763 +0000
+++ peertube/node_modules/pem/lib/pem.js 2022-04-06 13:59:48.916695687 +0000
@@ -74,7 +74,7 @@
params.push(keyBitsize)
- openssl.exec(params, 'RSA PRIVATE KEY', function (sslErr, key) {
+ openssl.exec(params, 'PRIVATE KEY', function (sslErr, key) {
function done (err) {
if (err) {
return callback(err)
Hope this will be useful to you.
Hi,
PeerTube already uses latest
pem
dependency. 🤔 You can check your version in/usr/share/peertube/node_modules/pem/package.json
After the Peertube installation, there is no folder peertube
under /usr/share
Have I missed something?
Here are my patches while waiting for an official solution:
--- peertube/dist/server/helpers/custom-validators/activitypub/actor.js.ori 2022-04-06 13:58:17.752681849 +0000 +++ peertube/dist/server/helpers/custom-validators/activitypub/actor.js 2022-04-06 13:58:22.268682531 +0000 @@ -43,8 +43,8 @@ function isActorPrivateKeyValid(privateKey) { return (0, misc_1.exists)(privateKey) && typeof privateKey === 'string' && - privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----') && - privateKey.includes('-----END RSA PRIVATE KEY-----') && + privateKey.startsWith('-----BEGIN PRIVATE KEY-----') && + privateKey.includes('-----END PRIVATE KEY-----') && validator_1.default.isLength(privateKey, constants_1.CONSTRAINTS_FIELDS.ACTORS.PRIVATE_KEY); } exports.isActorPrivateKeyValid = isActorPrivateKeyValid; --- peertube/node_modules/pem/lib/pem.js.ori 2022-04-06 13:59:36.232693763 +0000 +++ peertube/node_modules/pem/lib/pem.js 2022-04-06 13:59:48.916695687 +0000 @@ -74,7 +74,7 @@ params.push(keyBitsize) - openssl.exec(params, 'RSA PRIVATE KEY', function (sslErr, key) { + openssl.exec(params, 'PRIVATE KEY', function (sslErr, key) { function done (err) { if (err) { return callback(err)
Hope this will be useful to you.
How can I set your workaround? I have the same issue
Any news?
I continue having the same issue with the error during the user account creation.
I hope to have a reply from @GnunuX
@Chocobozzz I don't have this resource /usr/share/peertube/node_modules/pem/package.json
on my server, although I followed the installing instructions.
@nicfab Find the file to be patched.
If you followed the installation instructions, you may find it here.
/var/www/peertube/peertube-latest/server/helpers/custom-validators/activitypub/actor.ts
/var/www/peertube/peertube-latest/node_modules/pem/lib/pem.js
Next, apply the changes listed. Simply remove the string 'RSA ' in three places.
activitypub/
Thank you. Indeed, I was quite inattentive; the paths were in the previous message. I'm sorry.
However, I found only the second one (/var/www/peertube/peertube-latest/node_modules/pem/lib/pem.js
).
On my server, there isn't /var/www/peertube/peertube-latest/server/helpers/custom-validators/activitypub/actor.ts
Should I worry about it?
Should I worry about it?
No, /var/www/peertube/peertube-latest/server/helpers/custom-validators/activitypub/actor.ts
is a source file so it's normal that it's not available on prod servers.
Should I worry about it?
No,
/var/www/peertube/peertube-latest/server/helpers/custom-validators/activitypub/actor.ts
is a source file so it's normal that it's not available on prod servers.
Thank you.
Anyway, I remove 'RSA' from /var/www/peertube/peertube-latest/node_modules/pem/lib/pem.js
but I continue receiving the same error.
Here is that file. Can you tell if I did something wrong?
'use strict'
/**
* pem module
*
* @module pem
*/
const { promisify } = require('es6-promisify')
var net = require('net')
var helper = require('./helper.js')
var openssl = require('./openssl.js')
module.exports.createPrivateKey = createPrivateKey
module.exports.createDhparam = createDhparam
module.exports.createEcparam = createEcparam
module.exports.createCSR = createCSR
module.exports.createCertificate = createCertificate
module.exports.readCertificateInfo = readCertificateInfo
module.exports.getPublicKey = getPublicKey
module.exports.getFingerprint = getFingerprint
module.exports.getModulus = getModulus
module.exports.getDhparamInfo = getDhparamInfo
module.exports.createPkcs12 = createPkcs12
module.exports.readPkcs12 = readPkcs12
module.exports.verifySigningChain = verifySigningChain
module.exports.checkCertificate = checkCertificate
module.exports.checkPkcs12 = checkPkcs12
module.exports.config = config
/**
* quick access the convert module
* @type {module:convert}
*/
module.exports.convert = require('./convert.js')
var KEY_START = '-----BEGIN PRIVATE KEY-----'
var KEY_END = '-----END PRIVATE KEY-----'
var RSA_KEY_START = '-----BEGIN RSA PRIVATE KEY-----'
var RSA_KEY_END = '-----END RSA PRIVATE KEY-----'
var ENCRYPTED_KEY_START = '-----BEGIN ENCRYPTED PRIVATE KEY-----'
var ENCRYPTED_KEY_END = '-----END ENCRYPTED PRIVATE KEY-----'
var CERT_START = '-----BEGIN CERTIFICATE-----'
var CERT_END = '-----END CERTIFICATE-----'
/**
* Creates a private key
*
* @static
* @param {Number} [keyBitsize=2048] Size of the key, defaults to 2048bit
* @param {Object} [options] object of cipher and password {cipher:'aes128',password:'xxx'}, defaults empty object
* @param {String} [options.cipher] string of the cipher for the encryption - needed with password
* @param {String} [options.password] string of the cipher password for the encryption needed with cipher
* @param {Function} callback Callback function with an error object and {key}
*/
function createPrivateKey (keyBitsize, options, callback) {
if (!callback && !options && typeof keyBitsize === 'function') {
callback = keyBitsize
keyBitsize = undefined
options = {}
} else if (!callback && keyBitsize && typeof options === 'function') {
callback = options
options = {}
}
keyBitsize = Number(keyBitsize) || 2048
var params = ['genrsa']
var delTempPWFiles = []
if (options && options.cipher && (Number(helper.ciphers.indexOf(options.cipher)) !== -1) && options.password) {
helper.createPasswordFile({ cipher: options.cipher, password: options.password, passType: 'out' }, params, delTempPWFiles)
}
params.push(keyBitsize)
openssl.exec(params, 'PRIVATE KEY', function (sslErr, key) {
function done (err) {
if (err) {
return callback(err)
}
callback(null, {
key: key
})
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
}
/**
* Creates a dhparam key
*
* @static
* @param {Number} [keyBitsize=512] Size of the key, defaults to 512bit
* @param {Function} callback Callback function with an error object and {dhparam}
*/
function createDhparam (keyBitsize, callback) {
if (!callback && typeof keyBitsize === 'function') {
callback = keyBitsize
keyBitsize = undefined
}
keyBitsize = Number(keyBitsize) || 512
var params = ['dhparam',
'-outform',
'PEM',
keyBitsize
]
openssl.exec(params, 'DH PARAMETERS', function (error, dhparam) {
if (error) {
return callback(error)
}
return callback(null, {
dhparam: dhparam
})
})
}
/**
* Creates a ecparam key
* @static
* @param {String} [keyName=secp256k1] Name of the key, defaults to secp256k1
* @param {String} [paramEnc=explicit] Encoding of the elliptic curve parameters, defaults to explicit
* @param {Boolean} [noOut=false] This option inhibits the output of the encoded version of the parameters.
* @param {Function} callback Callback function with an error object and {ecparam}
*/
function createEcparam (keyName, paramEnc, noOut, callback) {
if (!callback && typeof noOut === 'undefined' && !paramEnc && typeof keyName === 'function') {
callback = keyName
keyName = undefined
} else if (!callback && typeof noOut === 'undefined' && keyName && typeof paramEnc === 'function') {
callback = paramEnc
paramEnc = undefined
} else if (!callback && typeof noOut === 'function' && keyName && paramEnc) {
callback = noOut
noOut = undefined
}
keyName = keyName || 'secp256k1'
paramEnc = paramEnc || 'explicit'
noOut = noOut || false
var params = ['ecparam',
'-name',
keyName,
'-genkey',
'-param_enc',
paramEnc
]
var searchString = 'EC PARAMETERS'
if (noOut) {
params.push('-noout')
searchString = 'EC PRIVATE KEY'
}
openssl.exec(params, searchString, function (error, ecparam) {
if (error) {
return callback(error)
}
return callback(null, {
ecparam: ecparam
})
})
}
/**
* Creates a Certificate Signing Request
* If client key is undefined, a new key is created automatically. The used key is included
* in the callback return as clientKey
* @static
* @param {Object} [options] Optional options object
* @param {String} [options.clientKey] Optional client key to use
* @param {Number} [options.keyBitsize] If clientKey is undefined, bit size to use for generating a new key (defaults to 2048)
* @param {String} [options.hash] Hash function to use (either md5 sha1 or sha256, defaults to sha256)
* @param {String} [options.country] CSR country field
* @param {String} [options.state] CSR state field
* @param {String} [options.locality] CSR locality field
* @param {String} [options.organization] CSR organization field
* @param {String} [options.organizationUnit] CSR organizational unit field
* @param {String} [options.commonName='localhost'] CSR common name field
* @param {String} [options.emailAddress] CSR email address field
* @param {String} [options.csrConfigFile] CSR config file
* @param {Array} [options.altNames] is a list of subjectAltNames in the subjectAltName field
* @param {Function} callback Callback function with an error object and {csr, clientKey}
*/
function createCSR (options, callback) {
if (!callback && typeof options === 'function') {
callback = options
options = undefined
}
options = options || {}
// http://stackoverflow.com/questions/14089872/why-does-node-js-accept-ip-addresses-in-certificates-only-for-san-not-for-cn
if (options.commonName && (net.isIPv4(options.commonName) || net.isIPv6(options.commonName))) {
if (!options.altNames) {
options.altNames = [options.commonName]
} else if (options.altNames.indexOf(options.commonName) === -1) {
options.altNames = options.altNames.concat([options.commonName])
}
}
if (!options.clientKey) {
createPrivateKey(options.keyBitsize || 2048, function (error, keyData) {
if (error) {
return callback(error)
}
options.clientKey = keyData.key
createCSR(options, callback)
})
return
}
var params = ['req',
'-new',
'-' + (options.hash || 'sha256')
]
if (options.csrConfigFile) {
params.push('-config')
params.push(options.csrConfigFile)
} else {
params.push('-subj')
params.push(generateCSRSubject(options))
}
params.push('-key')
params.push('--TMPFILE--')
var tmpfiles = [options.clientKey]
var config = null
if (options.altNames && Array.isArray(options.altNames) && options.altNames.length) {
params.push('-extensions')
params.push('v3_req')
params.push('-config')
params.push('--TMPFILE--')
var altNamesRep = []
for (var i = 0; i < options.altNames.length; i++) {
altNamesRep.push((net.isIP(options.altNames[i]) ? 'IP' : 'DNS') + '.' + (i + 1) + ' = ' + options.altNames[i])
}
tmpfiles.push(config = [
'[req]',
'req_extensions = v3_req',
'distinguished_name = req_distinguished_name',
'[v3_req]',
'subjectAltName = @alt_names',
'[alt_names]',
altNamesRep.join('\n'),
'[req_distinguished_name]',
'commonName = Common Name',
'commonName_max = 64'
].join('\n'))
} else if (options.config) {
config = options.config
}
var delTempPWFiles = []
if (options.clientKeyPassword) {
helper.createPasswordFile({ cipher: '', password: options.clientKeyPassword, passType: 'in' }, params, delTempPWFiles)
}
openssl.exec(params, 'CERTIFICATE REQUEST', tmpfiles, function (sslErr, data) {
function done (err) {
if (err) {
return callback(err)
}
callback(null, {
csr: data,
config: config,
clientKey: options.clientKey
})
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
}
/**
* Creates a certificate based on a CSR. If CSR is not defined, a new one
* will be generated automatically. For CSR generation all the options values
* can be used as with createCSR.
* @static
* @param {Object} [options] Optional options object
* @param {String} [options.serviceCertificate] PEM encoded certificate
* @param {String} [options.serviceKey] Private key for signing the certificate, if not defined a new one is generated
* @param {String} [options.serviceKeyPassword] Password of the service key
* @param {Boolean} [options.selfSigned] If set to true and serviceKey is not defined, use clientKey for signing
* @param {String|Number} [options.serial] Set a serial max. 20 octets - only together with options.serviceCertificate
* @param {String} [options.serialFile] Set the name of the serial file, without extension. - only together with options.serviceCertificate and never in tandem with options.serial
* @param {String} [options.hash] Hash function to use (either md5 sha1 or sha256, defaults to sha256)
* @param {String} [options.csr] CSR for the certificate, if not defined a new one is generated
* @param {Number} [options.days] Certificate expire time in days
* @param {String} [options.clientKeyPassword] Password of the client key
* @param {String} [options.extFile] extension config file - without '-extensions v3_req'
* @param {String} [options.config] extension config file - with '-extensions v3_req'
* @param {String} [options.csrConfigFile] CSR config file - only used if no options.csr is provided
* @param {Array} [options.altNames] is a list of subjectAltNames in the subjectAltName field - only used if no options.csr is provided
* @param {Function} callback Callback function with an error object and {certificate, csr, clientKey, serviceKey}
*/
function createCertificate (options, callback) {
if (!callback && typeof options === 'function') {
callback = options
options = undefined
}
options = options || {}
if (!options.csr) {
createCSR(options, function (error, keyData) {
if (error) {
return callback(error)
}
options.csr = keyData.csr
options.config = keyData.config
options.clientKey = keyData.clientKey
createCertificate(options, callback)
})
return
}
if (!options.clientKey) {
options.clientKey = ''
}
if (!options.serviceKey) {
if (options.selfSigned) {
options.serviceKey = options.clientKey
} else {
createPrivateKey(options.keyBitsize || 2048, function (error, keyData) {
if (error) {
return callback(error)
}
options.serviceKey = keyData.key
createCertificate(options, callback)
})
return
}
}
readCertificateInfo(options.csr, function (error2, data2) {
if (error2) {
return callback(error2)
}
var params = ['x509',
'-req',
'-' + (options.hash || 'sha256'),
'-days',
Number(options.days) || '365',
'-in',
'--TMPFILE--'
]
var tmpfiles = [options.csr]
var delTempPWFiles = []
if (options.serviceCertificate) {
params.push('-CA')
params.push('--TMPFILE--')
params.push('-CAkey')
params.push('--TMPFILE--')
if (options.serial) {
params.push('-set_serial')
if (helper.isNumber(options.serial)) {
// set the serial to the max lenth of 20 octets ()
// A certificate serial number is not decimal conforming. That is the
// bytes in a serial number do not necessarily map to a printable ASCII
// character.
// eg: 0x00 is a valid serial number and can not be represented in a
// human readable format (atleast one that can be directly mapped to
// the ACSII table).
params.push('0x' + ('0000000000000000000000000000000000000000' + options.serial.toString(16)).slice(-40))
} else {
if (helper.isHex(options.serial)) {
if (options.serial.startsWith('0x')) {
options.serial = options.serial.substring(2, options.serial.length)
}
params.push('0x' + ('0000000000000000000000000000000000000000' + options.serial).slice(-40))
} else {
params.push('0x' + ('0000000000000000000000000000000000000000' + helper.toHex(options.serial)).slice(-40))
}
}
} else {
params.push('-CAcreateserial')
if (options.serialFile) {
params.push('-CAserial')
params.push(options.serialFile + '.srl')
}
}
if (options.serviceKeyPassword) {
helper.createPasswordFile({ cipher: '', password: options.serviceKeyPassword, passType: 'in' }, params, delTempPWFiles)
}
tmpfiles.push(options.serviceCertificate)
tmpfiles.push(options.serviceKey)
} else {
params.push('-signkey')
params.push('--TMPFILE--')
if (options.serviceKeyPassword) {
helper.createPasswordFile({ cipher: '', password: options.serviceKeyPassword, passType: 'in' }, params, delTempPWFiles)
}
tmpfiles.push(options.serviceKey)
}
if (options.config) {
params.push('-extensions')
params.push('v3_req')
params.push('-extfile')
params.push('--TMPFILE--')
tmpfiles.push(options.config)
} else if (options.extFile) {
params.push('-extfile')
params.push(options.extFile)
} else {
var altNamesRep = []
if (data2 && data2.san) {
for (var i = 0; i < data2.san.dns.length; i++) {
altNamesRep.push('DNS' + '.' + (i + 1) + ' = ' + data2.san.dns[i])
}
for (var i2 = 0; i2 < data2.san.ip.length; i2++) {
altNamesRep.push('IP' + '.' + (i2 + 1) + ' = ' + data2.san.ip[i2])
}
for (var i3 = 0; i3 < data2.san.email.length; i3++) {
altNamesRep.push('email' + '.' + (i3 + 1) + ' = ' + data2.san.email[i3])
}
params.push('-extensions')
params.push('v3_req')
params.push('-extfile')
params.push('--TMPFILE--')
tmpfiles.push([
'[v3_req]',
'subjectAltName = @alt_names',
'[alt_names]',
altNamesRep.join('\n')
].join('\n'))
}
}
if (options.clientKeyPassword) {
helper.createPasswordFile({ cipher: '', password: options.clientKeyPassword, passType: 'in' }, params, delTempPWFiles)
}
openssl.exec(params, 'CERTIFICATE', tmpfiles, function (sslErr, data) {
function done (err) {
if (err) {
return callback(err)
}
var response = {
csr: options.csr,
clientKey: options.clientKey,
certificate: data,
serviceKey: options.serviceKey
}
return callback(null, response)
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
})
}
/**
* Exports a public key from a private key, CSR or certificate
* @static
* @param {String} certificate PEM encoded private key, CSR or certificate
* @param {Function} callback Callback function with an error object and {publicKey}
*/
function getPublicKey (certificate, callback) {
if (!callback && typeof certificate === 'function') {
callback = certificate
certificate = undefined
}
certificate = (certificate || '').toString()
var params
if (certificate.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)) {
params = ['req',
'-in',
'--TMPFILE--',
'-pubkey',
'-noout'
]
} else if (certificate.match(/BEGIN RSA PRIVATE KEY/) || certificate.match(/BEGIN PRIVATE KEY/)) {
params = ['rsa',
'-in',
'--TMPFILE--',
'-pubout'
]
} else {
params = ['x509',
'-in',
'--TMPFILE--',
'-pubkey',
'-noout'
]
}
openssl.exec(params, 'PUBLIC KEY', certificate, function (error, key) {
if (error) {
return callback(error)
}
return callback(null, {
publicKey: key
})
})
}
/**
* Reads subject data from a certificate or a CSR
* @static
* @param {String} certificate PEM encoded CSR or certificate
* @param {Function} callback Callback function with an error object and {country, state, locality, organization, organizationUnit, commonName, emailAddress}
*/
function readCertificateInfo (certificate, callback) {
if (!callback && typeof certificate === 'function') {
callback = certificate
certificate = undefined
}
certificate = (certificate || '').toString()
var isMatch = certificate.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)
var type = isMatch ? 'req' : 'x509'
var params = [type,
'-noout',
'-nameopt',
'RFC2253,sep_multiline,space_eq,-esc_msb,utf8',
'-text',
'-in',
'--TMPFILE--'
]
openssl.spawnWrapper(params, certificate, function (err, code, stdout, stderr) {
if (err) {
return callback(err)
} else if (stderr) {
return callback(stderr)
}
return fetchCertificateData(stdout, callback)
})
}
/**
* get the modulus from a certificate, a CSR or a private key
* @static
* @param {String} certificate PEM encoded, CSR PEM encoded, or private key
* @param {String} [password] password for the certificate
* @param {String} [hash] hash function to use (up to now `md5` supported) (default: none)
* @param {Function} callback Callback function with an error object and {modulus}
*/
function getModulus (certificate, password, hash, callback) {
if (!callback && !hash && typeof password === 'function') {
callback = password
password = undefined
hash = false
} else if (!callback && hash && typeof hash === 'function') {
callback = hash
hash = false
// password will be falsy if not provided
}
// adding hash function to params, is not supported by openssl.
// process piping would be the right way (... | openssl md5)
// No idea how this can be achieved in easy with the current build in methods
// of pem.
if (hash && hash !== 'md5') {
hash = false
}
certificate = (Buffer.isBuffer(certificate) && certificate.toString()) || certificate
var type = ''
if (certificate.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)) {
type = 'req'
} else if (certificate.match(/BEGIN RSA PRIVATE KEY/) || certificate.match(/BEGIN PRIVATE KEY/)) {
type = 'rsa'
} else {
type = 'x509'
}
var params = [
type,
'-noout',
'-modulus',
'-in',
'--TMPFILE--'
]
var delTempPWFiles = []
if (password) {
helper.createPasswordFile({ cipher: '', password: password, passType: 'in' }, params, delTempPWFiles)
}
openssl.spawnWrapper(params, certificate, function (sslErr, code, stdout, stderr) {
function done (err) {
if (err) {
return callback(err)
}
var match = stdout.match(/Modulus=([0-9a-fA-F]+)$/m)
if (match) {
return callback(null, {
modulus: hash ? require(hash)(match[1]) : match[1]
})
} else {
return callback(new Error('No modulus'))
}
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr || stderr)
})
})
}
/**
* get the size and prime of DH parameters
* @static
* @param {String} DH parameters PEM encoded
* @param {Function} callback Callback function with an error object and {size, prime}
*/
function getDhparamInfo (dh, callback) {
dh = (Buffer.isBuffer(dh) && dh.toString()) || dh
var params = [
'dhparam',
'-text',
'-in',
'--TMPFILE--'
]
openssl.spawnWrapper(params, dh, function (err, code, stdout, stderr) {
if (err) {
return callback(err)
} else if (stderr) {
return callback(stderr)
}
var result = {}
var match = stdout.match(/Parameters: \((\d+) bit\)/)
if (match) {
result.size = Number(match[1])
}
var prime = ''
stdout.split('\n').forEach(function (line) {
if (/\s+([0-9a-f][0-9a-f]:)+[0-9a-f]?[0-9a-f]?/g.test(line)) {
prime += line.trim()
}
})
if (prime) {
result.prime = prime
}
if (!match && !prime) {
return callback(new Error('No DH info found'))
}
return callback(null, result)
})
}
/**
* config the pem module
* @static
* @param {Object} options
*/
function config (options) {
Object.keys(options).forEach(function (k) {
openssl.set(k, options[k])
})
}
/**
* Gets the fingerprint for a certificate
* @static
* @param {String} PEM encoded certificate
* @param {String} [hash] hash function to use (either `md5`, `sha1` or `sha256`, defaults to `sha1`)
* @param {Function} callback Callback function with an error object and {fingerprint}
*/
function getFingerprint (certificate, hash, callback) {
if (!callback && typeof hash === 'function') {
callback = hash
hash = undefined
}
hash = hash || 'sha1'
var params = ['x509',
'-in',
'--TMPFILE--',
'-fingerprint',
'-noout',
'-' + hash
]
openssl.spawnWrapper(params, certificate, function (err, code, stdout, stderr) {
if (err) {
return callback(err)
} else if (stderr) {
return callback(stderr)
}
var match = stdout.match(/Fingerprint=([0-9a-fA-F:]+)$/m)
if (match) {
return callback(null, {
fingerprint: match[1]
})
} else {
return callback(new Error('No fingerprint'))
}
})
}
/**
* Export private key and certificate to a PKCS12 keystore
* @static
* @param {String} PEM encoded private key
* @param {String} PEM encoded certificate
* @param {String} Password of the result PKCS12 file
* @param {Object} [options] object of cipher and optional client key password {cipher:'aes128', clientKeyPassword: 'xxxx', certFiles: ['file1','file2']}
* @param {Function} callback Callback function with an error object and {pkcs12}
*/
function createPkcs12 (key, certificate, password, options, callback) {
if (!callback && typeof options === 'function') {
callback = options
options = {}
}
var params = ['pkcs12', '-export']
var delTempPWFiles = []
if (options.cipher && options.clientKeyPassword) {
// NOTICE: The password field is needed! self if it is empty.
// create password file for the import "-passin"
helper.createPasswordFile({ cipher: options.cipher, password: options.clientKeyPassword, passType: 'in' }, params, delTempPWFiles)
}
// NOTICE: The password field is needed! self if it is empty.
// create password file for the password "-password"
helper.createPasswordFile({ cipher: '', password: password, passType: 'word' }, params, delTempPWFiles)
params.push('-in')
params.push('--TMPFILE--')
params.push('-inkey')
params.push('--TMPFILE--')
var tmpfiles = [certificate, key]
if (options.certFiles) {
tmpfiles.push(options.certFiles.join(''))
params.push('-certfile')
params.push('--TMPFILE--')
}
openssl.execBinary(params, tmpfiles, function (sslErr, pkcs12) {
function done (err) {
if (err) {
return callback(err)
}
return callback(null, {
pkcs12: pkcs12
})
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
}
/**
* read sslcert data from Pkcs12 file. Results are provided in callback response in object notation ({cert: .., ca:..., key:...})
* @static
* @param {Buffer|String} bufferOrPath Buffer or path to file
* @param {Object} [options] openssl options
* @param {Function} callback Called with error object and sslcert bundle object
*/
function readPkcs12 (bufferOrPath, options, callback) {
if (!callback && typeof options === 'function') {
callback = options
options = {}
}
options.p12Password = options.p12Password || ''
var tmpfiles = []
var delTempPWFiles = []
var args = ['pkcs12', '-in', bufferOrPath]
helper.createPasswordFile({ cipher: '', password: options.p12Password, passType: 'in' }, args, delTempPWFiles)
if (Buffer.isBuffer(bufferOrPath)) {
tmpfiles = [bufferOrPath]
args[2] = '--TMPFILE--'
}
if (options.clientKeyPassword) {
helper.createPasswordFile({ cipher: '', password: options.clientKeyPassword, passType: 'out' }, args, delTempPWFiles)
} else {
args.push('-nodes')
}
openssl.execBinary(args, tmpfiles, function (sslErr, stdout) {
function done (err) {
var keybundle = {}
if (err && err.message.indexOf('No such file or directory') !== -1) {
err.code = 'ENOENT'
}
if (!err) {
var certs = readFromString(stdout, CERT_START, CERT_END)
keybundle.cert = certs.shift()
keybundle.ca = certs
keybundle.key = readFromString(stdout, KEY_START, KEY_END).pop()
if (keybundle.key) {
// convert to RSA key
return openssl.exec(['rsa', '-in', '--TMPFILE--'], 'RSA PRIVATE KEY', [keybundle.key], function (err, key) {
keybundle.key = key
return callback(err, keybundle)
})
}
if (options.clientKeyPassword) {
keybundle.key = readFromString(stdout, ENCRYPTED_KEY_START, ENCRYPTED_KEY_END).pop()
} else {
keybundle.key = readFromString(stdout, RSA_KEY_START, RSA_KEY_END).pop()
}
}
return callback(err, keybundle)
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
}
/**
* Check a certificate
* @static
* @param {String} PEM encoded certificate
* @param {String} [passphrase] password for the certificate
* @param {Function} callback Callback function with an error object and a boolean valid
*/
function checkCertificate (certificate, passphrase, callback) {
var params
var delTempPWFiles = []
if (!callback && typeof passphrase === 'function') {
callback = passphrase
passphrase = undefined
}
certificate = (certificate || '').toString()
if (certificate.match(/BEGIN(\sNEW)? CERTIFICATE REQUEST/)) {
params = ['req', '-text', '-noout', '-verify', '-in', '--TMPFILE--']
} else if (certificate.match(/BEGIN RSA PRIVATE KEY/) || certificate.match(/BEGIN PRIVATE KEY/)) {
params = ['rsa', '-noout', '-check', '-in', '--TMPFILE--']
} else {
params = ['x509', '-text', '-noout', '-in', '--TMPFILE--']
}
if (passphrase) {
helper.createPasswordFile({ cipher: '', password: passphrase, passType: 'in' }, params, delTempPWFiles)
}
openssl.spawnWrapper(params, certificate, function (sslErr, code, stdout, stderr) {
function done (err) {
if (err && err.toString().trim() !== 'verify OK') {
return callback(err)
}
var result
switch (params[0]) {
case 'rsa':
result = /^Rsa key ok$/i.test(stdout.trim())
break
default:
result = /Signature Algorithm/im.test(stdout)
break
}
callback(null, result)
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr || stderr)
})
})
}
/**
* check a PKCS#12 file (.pfx or.p12)
* @static
* @param {Buffer|String} bufferOrPath PKCS#12 certificate
* @param {String} [passphrase] optional passphrase which will be used to open the keystore
* @param {Function} callback Callback function with an error object and a boolean valid
*/
function checkPkcs12 (bufferOrPath, passphrase, callback) {
if (!callback && typeof passphrase === 'function') {
callback = passphrase
passphrase = ''
}
var tmpfiles = []
var delTempPWFiles = []
var args = ['pkcs12', '-info', '-in', bufferOrPath, '-noout', '-maciter', '-nodes']
helper.createPasswordFile({ cipher: '', password: passphrase, passType: 'in' }, args, delTempPWFiles)
if (Buffer.isBuffer(bufferOrPath)) {
tmpfiles = [bufferOrPath]
args[3] = '--TMPFILE--'
}
openssl.spawnWrapper(args, tmpfiles, function (sslErr, code, stdout, stderr) {
function done (err) {
if (err) {
return callback(err)
}
callback(null, (/MAC verified OK/im.test(stderr) || (!(/MAC verified OK/im.test(stderr)) && !(/Mac verify error/im.test(stderr)))))
}
helper.deleteTempFiles(delTempPWFiles, function (fsErr) {
done(sslErr || fsErr)
})
})
}
/**
* Verifies the signing chain of the passed certificate
* @static
* @param {String|Array} PEM encoded certificate include intermediate certificates
* @param {String|Array} [List] of CA certificates
* @param {Function} callback Callback function with an error object and a boolean valid
*/
function verifySigningChain (certificate, ca, callback) {
if (!callback && typeof ca === 'function') {
callback = ca
ca = undefined
}
if (!Array.isArray(certificate)) {
certificate = [certificate]
}
if (!Array.isArray(ca) && ca !== undefined) {
if (ca !== '') {
ca = [ca]
}
}
var files = []
if (ca !== undefined) {
// ca certificates
files.push(ca.join('\n'))
}
// certificate incl. intermediate certificates
files.push(certificate.join('\n'))
var params = ['verify']
if (ca !== undefined) {
// ca certificates
params.push('-CAfile')
params.push('--TMPFILE--')
}
// certificate incl. intermediate certificates
params.push('--TMPFILE--')
openssl.spawnWrapper(params, files, function (err, code, stdout, stderr) {
if (err) {
return callback(err)
}
callback(null, stdout.trim().slice(-4) === ': OK')
})
}
// HELPER FUNCTIONS
function fetchCertificateData (certData, callback) {
// try catch : if something will fail in parsing it won't crash the calling code
try {
certData = (certData || '').toString()
var serial, subject, tmp, issuer
var certValues = {
issuer: {}
}
var validity = {}
var san
var ky, i
// serial
if ((serial = certData.match(/\s*Serial Number:\r?\n?\s*([^\r\n]*)\r?\n\s*\b/)) && serial.length > 1) {
certValues.serial = serial[1]
}
if ((subject = certData.match(/\s*Subject:\r?\n(\s*(([a-zA-Z0-9.]+)\s=\s[^\r\n]+\r?\n))*\s*\b/)) && subject.length > 1) {
subject = subject[0]
tmp = matchAll(subject, /\s([a-zA-Z0-9.]+)\s=\s([^\r\n].*)/g)
if (tmp) {
for (i = 0; i < tmp.length; i++) {
ky = tmp[i][1].trim()
if (ky.match('(C|ST|L|O|OU|CN|emailAddress|DC)') || ky === '') {
continue
}
certValues[ky] = tmp[i][2].trim()
}
}
// country
tmp = subject.match(/\sC\s=\s([^\r\n].*?)[\r\n]/)
certValues.country = (tmp && tmp[1]) || ''
// state
tmp = subject.match(/\sST\s=\s([^\r\n].*?)[\r\n]/)
certValues.state = (tmp && tmp[1]) || ''
// locality
tmp = subject.match(/\sL\s=\s([^\r\n].*?)[\r\n]/)
certValues.locality = (tmp && tmp[1]) || ''
// organization
tmp = matchAll(subject, /\sO\s=\s([^\r\n].*)/g)
certValues.organization = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// unit
tmp = matchAll(subject, /\sOU\s=\s([^\r\n].*)/g)
certValues.organizationUnit = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// common name
tmp = matchAll(subject, /\sCN\s=\s([^\r\n].*)/g)
certValues.commonName = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// email
tmp = matchAll(subject, /emailAddress\s=\s([^\r\n].*)/g)
certValues.emailAddress = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// DC name
tmp = matchAll(subject, /\sDC\s=\s([^\r\n].*)/g)
certValues.dc = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
}
if ((issuer = certData.match(/\s*Issuer:\r?\n(\s*([a-zA-Z0-9.]+)\s=\s[^\r\n].*\r?\n)*\s*\b/)) && issuer.length > 1) {
issuer = issuer[0]
tmp = matchAll(issuer, /\s([a-zA-Z0-9.]+)\s=\s([^\r\n].*)/g)
for (i = 0; i < tmp.length; i++) {
ky = tmp[i][1].toString()
if (ky.match('(C|ST|L|O|OU|CN|emailAddress|DC)')) {
continue
}
certValues.issuer[ky] = tmp[i][2].toString()
}
// country
tmp = issuer.match(/\sC\s=\s([^\r\n].*?)[\r\n]/)
certValues.issuer.country = (tmp && tmp[1]) || ''
// state
tmp = issuer.match(/\sST\s=\s([^\r\n].*?)[\r\n]/)
certValues.issuer.state = (tmp && tmp[1]) || ''
// locality
tmp = issuer.match(/\sL\s=\s([^\r\n].*?)[\r\n]/)
certValues.issuer.locality = (tmp && tmp[1]) || ''
// organization
tmp = matchAll(issuer, /\sO\s=\s([^\r\n].*)/g)
certValues.issuer.organization = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// unit
tmp = matchAll(issuer, /\sOU\s=\s([^\r\n].*)/g)
certValues.issuer.organizationUnit = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var
r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// common name
tmp = matchAll(issuer, /\sCN\s=\s([^\r\n].*)/g)
certValues.issuer.commonName = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var
r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
// DC name
tmp = matchAll(issuer, /\sDC\s=\s([^\r\n].*)/g)
certValues.issuer.dc = tmp ? (tmp.length > 1 ? tmp.sort(function (t, n) {
var e = t[1].toUpperCase()
var
r = n[1].toUpperCase()
return r > e ? -1 : e > r ? 1 : 0
}).sort(function (t, n) {
return t[1].length - n[1].length
}).map(function (t) {
return t[1]
}) : tmp[0][1]) : ''
}
// SAN
if ((san = certData.match(/X509v3 Subject Alternative Name: \r?\n([^\r\n]*)\r?\n/)) && san.length > 1) {
san = san[1].trim() + '\n'
certValues.san = {}
// hostnames
tmp = pregMatchAll('DNS:([^,\\r\\n].*?)[,\\r\\n\\s]', san)
certValues.san.dns = tmp || ''
// IP-Addresses IPv4 & IPv6
tmp = pregMatchAll('IP Address:([^,\\r\\n].*?)[,\\r\\n\\s]', san)
certValues.san.ip = tmp || ''
// Email Addresses
tmp = pregMatchAll('email:([^,\\r\\n].*?)[,\\r\\n\\s]', san)
certValues.san.email = tmp || ''
}
// Validity
if ((tmp = certData.match(/Not Before\s?:\s?([^\r\n]*)\r?\n/)) && tmp.length > 1) {
validity.start = Date.parse((tmp && tmp[1]) || '')
}
if ((tmp = certData.match(/Not After\s?:\s?([^\r\n]*)\r?\n/)) && tmp.length > 1) {
validity.end = Date.parse((tmp && tmp[1]) || '')
}
if (validity.start && validity.end) {
certValues.validity = validity
}
// Validity end
// Signature Algorithm
if ((tmp = certData.match(/Signature Algorithm: ([^\r\n]*)\r?\n/)) && tmp.length > 1) {
certValues.signatureAlgorithm = (tmp && tmp[1]) || ''
}
// Public Key
if ((tmp = certData.match(/Public[ -]Key: ([^\r\n]*)\r?\n/)) && tmp.length > 1) {
certValues.publicKeySize = ((tmp && tmp[1]) || '').replace(/[()]/g, '')
}
// Public Key Algorithm
if ((tmp = certData.match(/Public Key Algorithm: ([^\r\n]*)\r?\n/)) && tmp.length > 1) {
certValues.publicKeyAlgorithm = (tmp && tmp[1]) || ''
}
callback(null, certValues)
} catch (err) {
callback(err)
}
}
function matchAll (str, regexp) {
var matches = []
str.replace(regexp, function () {
var arr = ([]).slice.call(arguments, 0)
var extras = arr.splice(-2)
arr.index = extras[0]
arr.input = extras[1]
matches.push(arr)
})
return matches.length ? matches : null
}
function pregMatchAll (regex, haystack) {
var globalRegex = new RegExp(regex, 'g')
var globalMatch = haystack.match(globalRegex) || []
var matchArray = []
var nonGlobalRegex, nonGlobalMatch
for (var i = 0; i < globalMatch.length; i++) {
nonGlobalRegex = new RegExp(regex)
nonGlobalMatch = globalMatch[i].match(nonGlobalRegex)
matchArray.push(nonGlobalMatch[1])
}
return matchArray
}
function generateCSRSubject (options) {
options = options || {}
var csrData = {
C: options.country || options.C,
ST: options.state || options.ST,
L: options.locality || options.L,
O: options.organization || options.O,
OU: options.organizationUnit || options.OU,
CN: options.commonName || options.CN || 'localhost',
DC: options.dc || options.DC || '',
emailAddress: options.emailAddress
}
var csrBuilder = Object.keys(csrData).map(function (key) {
if (csrData[key]) {
if (typeof csrData[key] === 'object' && csrData[key].length >= 1) {
var tmpStr = ''
csrData[key].map(function (o) {
tmpStr += '/' + key + '=' + o.replace(/[^\w .*\-,@']+/g, ' ').trim()
})
return tmpStr
} else {
return '/' + key + '=' + csrData[key].replace(/[^\w .*\-,@']+/g, ' ').trim()
}
}
})
return csrBuilder.join('')
}
function readFromString (string, start, end) {
if (Buffer.isBuffer(string)) {
string = string.toString('utf8')
}
var output = []
if (!string) {
return output
}
var offset = string.indexOf(start)
while (offset !== -1) {
string = string.substring(offset)
var endOffset = string.indexOf(end)
if (endOffset === -1) {
break
}
endOffset += end.length
output.push(string.substring(0, endOffset))
offset = string.indexOf(start, endOffset)
}
return output
}
// promisify not tested yet
/**
* Verifies the signing chain of the passed certificate
* @namespace
* @name promisified
* @property {function} createPrivateKey @see createPrivateKey
* @property {function} createDhparam - The default number of players.
* @property {function} createEcparam - The default level for the party.
* @property {function} createCSR - The default treasure.
* @property {function} createCertificate - How much gold the party starts with.
*/
module.exports.promisified = {
createPrivateKey: promisify(createPrivateKey),
createDhparam: promisify(createDhparam),
createEcparam: promisify(createEcparam),
createCSR: promisify(createCSR),
createCertificate: promisify(createCertificate),
readCertificateInfo: promisify(readCertificateInfo),
getPublicKey: promisify(getPublicKey),
getFingerprint: promisify(getFingerprint),
getModulus: promisify(getModulus),
getDhparamInfo: promisify(getDhparamInfo),
createPkcs12: promisify(createPkcs12),
readPkcs12: promisify(readPkcs12),
verifySigningChain: promisify(verifySigningChain),
checkCertificate: promisify(checkCertificate),
checkPkcs12: promisify(checkPkcs12)
}
Patch by @GnunuX worked for me on an Ubuntu 22.04 installation
Hello,
We should now support openssl v3 with https://github.com/Chocobozzz/PeerTube/commit/5d7cb63ede7c4bba93954c0586f589ad9748d5ea
Hello,
We should now support openssl v3 with 5d7cb63
Will it be available in the next release?
Will it be available in the next release?
Yes
Hello, I just installed an instance and I have the same error. Do you know when you will release the next release?
No sorry we don't have an ETA
What is the solution to install peertube before the release? change the version of ubuntu? change peertube version?
Try nightly builds: https://builds.joinpeertube.org/nightly/
Good well always the same... even with the nightly version I'm waiting for the new version looking forward
what is your error?
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.015 #033[33mwarn#033[39m: Directory of tmp should not be in the production directory of PeerTube. Please >
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.019 #033[33mwarn#033[39m: Directory of bin should not be in the production directory of PeerTube. Please >
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.020 #033[33mwarn#033[39m: Directory of avatars should not be in the production directory of PeerTube. Ple>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.021 #033[33mwarn#033[39m: Directory of videos should not be in the production directory of PeerTube. Plea>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.022 #033[33mwarn#033[39m: Directory of streaming_playlists should not be in the production directory of P>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.023 #033[33mwarn#033[39m: Directory of redundancy should not be in the production directory of PeerTube. >
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.023 #033[33mwarn#033[39m: Directory of logs should not be in the production directory of PeerTube. Please>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.024 #033[33mwarn#033[39m: Directory of previews should not be in the production directory of PeerTube. Pl>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.025 #033[33mwarn#033[39m: Directory of thumbnails should not be in the production directory of PeerTube. >
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.026 #033[33mwarn#033[39m: Directory of torrents should not be in the production directory of PeerTube. Pl>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.027 #033[33mwarn#033[39m: Directory of captions should not be in the production directory of PeerTube. Pl>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.027 #033[33mwarn#033[39m: Directory of cache should not be in the production directory of PeerTube. Pleas>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.028 #033[33mwarn#033[39m: Directory of plugins should not be in the production directory of PeerTube. Ple>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.029 #033[33mwarn#033[39m: Directory of client_overrides should not be in the production directory of Peer>
Jul 20 21:31:22 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:22.994 #033[32minfo#033[39m: Database peertube_prod is ready.
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.711 #033[32minfo#033[39m: Creating application account.
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.723 #033[32minfo#033[39m: Creating a default OAuth Client.
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.733 #033[32minfo#033[39m: Creating the administrator.
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.760 #033[32minfo#033[39m: Client id: xxxxxxxx
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.761 #033[32minfo#033[39m: Client secret: xxxxxxxxxx
Jul 20 21:31:24 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:24.842 #033[32minfo#033[39m: Generating a RSA key...
Jul 20 21:31:25 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:25.096 #033[32minfo#033[39m: Generating a RSA key...
Jul 20 21:31:25 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:25.100 #033[32minfo#033[39m: Generating a RSA key...
Jul 20 21:31:25 server13 peertube[44958]: [server13.tk:9000] 2022-07-20 21:31:25.486 #033[31merror#033[39m: Cannot install application. {
Jul 20 21:31:25 server13 peertube[44958]: "err": {
Jul 20 21:31:25 server13 peertube[44958]: "stack": "Error: RSA PRIVATE KEY not found from openssl output:\n---stdout---\n-----BEGIN PRIVATE KEY-----\nxXXXXXXXXXXXXXXXXXXXXX>
Jul 20 21:31:25 server13 peertube[44958]: "message": "RSA PRIVATE KEY not found from openssl output:\n---stdout---\n-----BEGIN PRIVATE KEY-----\nxXXXXXXXXXXXXXXXXXXXXXX>
Jul 20 21:31:25 server13 peertube[44958]: }
Jul 20 21:31:25 server13 peertube[44958]: }
Jul 20 21:31:25 server13 systemd[1]: peertube.service: Main process exited, code=exited, status=255/EXCEPTION
Jul 20 21:31:25 server13 systemd[1]: peertube.service: Failed with result 'exit-code'.
Jul 20 21:31:25 server13 systemd[1]: peertube.service: Consumed 5.751s CPU time.
Jul 20 21:31:25 server13 systemd[1]: peertube.service: Scheduled restart job, restart counter is at 1.
Jul 20 21:31:25 server13 systemd[1]: Stopped PeerTube daemon.
Jul 20 21:31:25 server13 systemd[1]: peertube.service: Consumed 5.751s CPU time.
Jul 20 21:31:25 server13 systemd[1]: Started PeerTube daemon.r
After this I change root password with cli and i have another error when i try to connect to peertube
Jul 20 21:27:56 server13 peertube[40310]: [server13.tk:9000] 2022-07-20 21:27:56.557 #033[33mwarn#033[39m: Login error {
Jul 20 21:27:56 server13 peertube[40310]: "err": {
Jul 20 21:27:56 server13 peertube[40310]: "statusCode": 400,
Jul 20 21:27:56 server13 peertube[40310]: "status": 400,
Jul 20 21:27:56 server13 peertube[40310]: "code": 400,
Jul 20 21:27:56 server13 peertube[40310]: "message": "Invalid client: client is invalid",
Jul 20 21:27:56 server13 peertube[40310]: "name": "invalid_client",
Jul 20 21:27:56 server13 peertube[40310]: "stack": "invalid_client: Invalid client: client is invalid\n at new InvalidClientError (/var/www/peertube/versions/peertube-v4.2.2/nod>
Jul 20 21:27:56 server13 peertube[40310]: }
Jul 20 21:27:56 server13 peertube[40310]: }
Are you sure you use the latest nightly build?
Indeed that was it. I manage to generate the certificate and I see well in the root password logs. But I still get the same error when I try to login.
Jul 25 21:27:56 server13 peertube[40310]: [server13.tk:9000] 2022-07-20 21:27:56.557 #033[33mwarn#033[39m: Login error {
Jul 25 21:27:56 server13 peertube[40310]: "err": {
Jul 25 21:27:56 server13 peertube[40310]: "statusCode": 400,
Jul 25 21:27:56 server13 peertube[40310]: "status": 400,
Jul 25 21:27:56 server13 peertube[40310]: "code": 400,
Jul 25 21:27:56 server13 peertube[40310]: "message": "Invalid client: client is invalid",
Jul 25 21:27:56 server13 peertube[40310]: "name": "invalid_client",
Jul 25 21:27:56 server13 peertube[40310]: "stack": "invalid_client: Invalid client: client is invalid\n at new InvalidClientError (/var/www/peertube/versions/peertube-nightly-2022-07-25/nod>
Jul 25 21:27:56 server13 peertube[40310]: }
Jul 25 21:27:56 server13 peertube[40310]: }
I don't think it's related. Please fill a new issue and fill the bug template
Describe the current behavior
The "openssl genrsa" command generates certificates in pkcs8 since version 3.0.0 of openssl:
The command line utilities genrsa and rsa have been modified to use PKEY APIs. They now write PKCS#8 keys by default. These commands are now in maintenance mode and no new features will be added to them.
pem project support openssl 3.0.0 since 1.14.5: https://github.com/Dexus/pem/commit/7ec825744b9cf1a9cab37983302fa6d7da8a9b22
Unfortunately Peertube has dependency for "pem" version "^1.12.3"
The error message:
Steps to reproduce:
1.Install openssl v3.0.0
Describe the expected behavior
Additional information