summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/util
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/lib/util
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloadUXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/lib/util')
-rw-r--r--security/nss/lib/util/SECerrs.h50
-rw-r--r--security/nss/lib/util/nssutil.h6
-rw-r--r--security/nss/lib/util/pkcs11n.h78
-rw-r--r--security/nss/lib/util/pkcs11t.h20
-rw-r--r--security/nss/lib/util/secoid.c17
-rw-r--r--security/nss/lib/util/secoidt.h3
-rw-r--r--security/nss/lib/util/secport.h5
-rw-r--r--security/nss/lib/util/utilmod.c5
8 files changed, 155 insertions, 29 deletions
diff --git a/security/nss/lib/util/SECerrs.h b/security/nss/lib/util/SECerrs.h
index 6d6f1b868..206fca087 100644
--- a/security/nss/lib/util/SECerrs.h
+++ b/security/nss/lib/util/SECerrs.h
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-/* General security error codes */
+/* General security error codes */
/* Caller must #include "secerr.h" */
ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
@@ -54,7 +54,7 @@ ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
"The security password entered is incorrect.")
ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
- "New password entered incorrectly. Please try again.")
+ "New password entered incorrectly. Please try again.")
ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
"security library: no nodelock.")
@@ -96,10 +96,10 @@ ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
"Cert Library: No Response")
ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
- "The certificate issuer's certificate has expired. Check your system date and time.")
+ "The certificate issuer's certificate has expired. Check your system date and time.")
ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
- "The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
+ "The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
"The CRL for the certificate's issuer has an invalid signature.")
@@ -159,7 +159,7 @@ ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
/* Fortezza Alerts */
ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
- "Fortezza card has not been properly initialized. \
+ "Fortezza card has not been properly initialized. \
Please remove it and return it to your issuer.")
ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
@@ -245,31 +245,31 @@ ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
"Error attempting to import certificates.")
ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
- "Unable to import. Decoding error. File not valid.")
+ "Unable to import. Decoding error. File not valid.")
ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
- "Unable to import. Invalid MAC. Incorrect password or corrupt file.")
+ "Unable to import. Invalid MAC. Incorrect password or corrupt file.")
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
- "Unable to import. MAC algorithm not supported.")
+ "Unable to import. MAC algorithm not supported.")
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, (SEC_ERROR_BASE + 81),
- "Unable to import. Only password integrity and privacy modes supported.")
+ "Unable to import. Only password integrity and privacy modes supported.")
ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
- "Unable to import. File structure is corrupt.")
+ "Unable to import. File structure is corrupt.")
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
- "Unable to import. Encryption algorithm not supported.")
+ "Unable to import. Encryption algorithm not supported.")
ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
- "Unable to import. File version not supported.")
+ "Unable to import. File version not supported.")
ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, (SEC_ERROR_BASE + 85),
- "Unable to import. Incorrect privacy password.")
+ "Unable to import. Incorrect privacy password.")
ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
- "Unable to import. Same nickname already exists in database.")
+ "Unable to import. Same nickname already exists in database.")
ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
"The user pressed cancel.")
@@ -290,34 +290,34 @@ ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
"Address in signing certificate does not match address in message headers.")
ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
- "Unable to import. Error attempting to import private key.")
+ "Unable to import. Error attempting to import private key.")
ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
- "Unable to import. Error attempting to import certificate chain.")
+ "Unable to import. Error attempting to import certificate chain.")
ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
- "Unable to export. Unable to locate certificate or key by nickname.")
+ "Unable to export. Unable to locate certificate or key by nickname.")
ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
- "Unable to export. Private Key could not be located and exported.")
+ "Unable to export. Private Key could not be located and exported.")
ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
- "Unable to export. Unable to write the export file.")
+ "Unable to export. Unable to write the export file.")
ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
- "Unable to import. Unable to read the import file.")
+ "Unable to import. Unable to read the import file.")
ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
- "Unable to export. Key database corrupt or deleted.")
+ "Unable to export. Key database corrupt or deleted.")
ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
"Unable to generate public/private key pair.")
ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
- "Password entered is invalid. Please pick a different one.")
+ "Password entered is invalid. Please pick a different one.")
ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
- "Old password entered incorrectly. Please try again.")
+ "Old password entered incorrectly. Please try again.")
ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
"Certificate nickname already in use.")
@@ -344,7 +344,7 @@ ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110),
"New KRL is not later than the current one.")
ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111),
- "New CKL has different issuer than current CKL. Delete current CKL.")
+ "New CKL has different issuer than current CKL. Delete current CKL.")
ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
"The Certifying Authority for this certificate is not permitted to issue a \
@@ -518,7 +518,7 @@ ER3(SEC_ERROR_PKCS11_GENERAL_ERROR, (SEC_ERROR_BASE + 167),
"A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
ER3(SEC_ERROR_PKCS11_FUNCTION_FAILED, (SEC_ERROR_BASE + 168),
- "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
+ "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.")
ER3(SEC_ERROR_PKCS11_DEVICE_ERROR, (SEC_ERROR_BASE + 169),
"A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h
index 44226cfeb..bbfec5000 100644
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -19,10 +19,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
-#define NSSUTIL_VERSION "3.41.4"
+#define NSSUTIL_VERSION "3.48"
#define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 41
-#define NSSUTIL_VPATCH 4
+#define NSSUTIL_VMINOR 48
+#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
diff --git a/security/nss/lib/util/pkcs11n.h b/security/nss/lib/util/pkcs11n.h
index 399d656a8..7fbfb780c 100644
--- a/security/nss/lib/util/pkcs11n.h
+++ b/security/nss/lib/util/pkcs11n.h
@@ -94,6 +94,8 @@
#define CKA_NSS_JPAKE_X2S (CKA_NSS + 33)
#define CKA_NSS_MOZILLA_CA_POLICY (CKA_NSS + 34)
+#define CKA_NSS_SERVER_DISTRUST_AFTER (CKA_NSS + 35)
+#define CKA_NSS_EMAIL_DISTRUST_AFTER (CKA_NSS + 36)
/*
* Trust attributes:
@@ -230,6 +232,16 @@
#define CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN (CKM_NSS + 31)
#define CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN (CKM_NSS + 32)
+#define CKM_NSS_CHACHA20_CTR (CKM_NSS + 33)
+
+/* IKE mechanism (to be proposed to PKCS #11 */
+#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 34)
+#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 35)
+#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 36)
+#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 37)
+
+#define CKM_NSS_PUB_FROM_PRIV (CKM_NSS + 40)
+
/*
* HISTORICAL:
* Do not attempt to use these. They are only used by NETSCAPE's internal
@@ -342,6 +354,72 @@ typedef struct CK_NSS_HKDFParams {
} CK_NSS_HKDFParams;
/*
+ * CK_NSS_IKE_PRF_PLUS_PARAMS is a structure that provides the parameters to
+ * the CKM_NSS_IKE_PRF_PLUS_DERIVE mechanism.
+ * The fields of the structure have the following meanings:
+ * prfMechanism underlying MAC mechanism used to generate the prf.
+ * bHasSeedKey hSeed key is present.
+ * hSeedKey optional seed from key
+ * pSeedData optional seed from data.
+ * ulSeedDataLen length of optional seed data.
+ * If no seed data is present this value is NULL.
+ */
+typedef struct CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE prfMechanism;
+ CK_BBOOL bHasSeedKey;
+ CK_OBJECT_HANDLE hSeedKey;
+ CK_BYTE_PTR pSeedData;
+ CK_ULONG ulSeedDataLen;
+} CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS;
+
+/* CK_NSS_IKE_PRF_DERIVE_PARAMS is a structure that provides the parameters to
+ * the CKM_NSS_IKE_PRF_DERIVE mechanism.
+ *
+ * The fields of the structure have the following meanings:
+ * prfMechanism underlying MAC mechanism used to generate the prf.
+ * bRekey hNewKey is present.
+ * pNi Ni value
+ * ulNiLen length of Ni
+ * pNr Nr value
+ * ulNrLen length of Nr
+ * hNewKey New key value to drive the rekey.
+ */
+typedef struct CK_NSS_IKE_PRF_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE prfMechanism;
+ CK_BBOOL bDataAsKey;
+ CK_BBOOL bRekey;
+ CK_BYTE_PTR pNi;
+ CK_ULONG ulNiLen;
+ CK_BYTE_PTR pNr;
+ CK_ULONG ulNrLen;
+ CK_OBJECT_HANDLE hNewKey;
+} CK_NSS_IKE_PRF_DERIVE_PARAMS;
+
+/* CK_NSS_IKE1_PRF_DERIVE_PARAMS is a structure that provides the parameters
+ * to the CKM_NSS_IKE_PRF_DERIVE mechanism.
+ *
+ * The fields of the structure have the following meanings:
+ * prfMechanism underlying MAC mechanism used to generate the prf.
+ * bRekey hNewKey is present.
+ * pCKYi CKYi value
+ * ulCKYiLen length of CKYi
+ * pCKYr CKYr value
+ * ulCKYrLen length of CKYr
+ * hNewKey New key value to drive the rekey.
+ */
+typedef struct CK_NSS_IKE1_PRF_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE prfMechanism;
+ CK_BBOOL bHasPrevKey;
+ CK_OBJECT_HANDLE hKeygxy;
+ CK_OBJECT_HANDLE hPrevKey;
+ CK_BYTE_PTR pCKYi;
+ CK_ULONG ulCKYiLen;
+ CK_BYTE_PTR pCKYr;
+ CK_ULONG ulCKYrLen;
+ CK_BYTE keyNumber;
+} CK_NSS_IKE1_PRF_DERIVE_PARAMS;
+
+/*
* Parameter for the TLS extended master secret key derivation mechanisms:
*
* * CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE
diff --git a/security/nss/lib/util/pkcs11t.h b/security/nss/lib/util/pkcs11t.h
index 01ff8a572..d57da409a 100644
--- a/security/nss/lib/util/pkcs11t.h
+++ b/security/nss/lib/util/pkcs11t.h
@@ -313,6 +313,7 @@ typedef CK_ULONG CK_OBJECT_CLASS;
/* CKO_HW_FEATURE is new for v2.10 */
/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
/* CKO_MECHANISM is new for v2.20 */
+/* CKO_PROFILE is new for v3.00 */
#define CKO_DATA 0x00000000
#define CKO_CERTIFICATE 0x00000001
#define CKO_PUBLIC_KEY 0x00000002
@@ -321,10 +322,23 @@ typedef CK_ULONG CK_OBJECT_CLASS;
#define CKO_HW_FEATURE 0x00000005
#define CKO_DOMAIN_PARAMETERS 0x00000006
#define CKO_MECHANISM 0x00000007
+#define CKO_PROFILE 0x00000009
#define CKO_VENDOR_DEFINED 0x80000000
typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+/* CK_PROFILE_ID is new for v3.00. CK_PROFILE_ID is a value that
+ * identifies the profile that the token supports. */
+typedef CK_ULONG CK_PROFILE_ID;
+
+/* Profile ID's */
+#define CKP_INVALID_ID 0x00000000UL
+#define CKP_BASELINE_PROVIDER 0x00000001UL
+#define CKP_EXTENDED_PROVIDER 0x00000002UL
+#define CKP_AUTHENTICATION_TOKEN 0x00000003UL
+#define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL
+#define CKP_VENDOR_DEFINED 0x80000000UL
+
/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
* value that identifies the hardware feature type of an object
* with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
@@ -536,6 +550,7 @@ typedef CK_ULONG CK_ATTRIBUTE_TYPE;
#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x00000600)
+#define CKA_PROFILE_ID 0x00000601UL
#define CKA_VENDOR_DEFINED 0x80000000
@@ -882,6 +897,11 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
#define CKM_AES_GCM 0x00001087
#define CKM_AES_CCM 0x00001088
#define CKM_AES_CTS 0x00001089
+/* AES-CMAC values copied from v2.40 errata 1 header file */
+#define CKM_AES_CMAC_GENERAL 0x0000108A
+#define CKM_AES_CMAC 0x0000108B
+#define CKM_AES_XCBC_MAC 0x0000108C
+#define CKM_AES_XCBC_MAC_96 0x0000108D
/* BlowFish and TwoFish are new for v2.20 */
#define CKM_BLOWFISH_KEY_GEN 0x00001090
diff --git a/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c
index 06b0cbcc4..2938b8ff1 100644
--- a/security/nss/lib/util/secoid.c
+++ b/security/nss/lib/util/secoid.c
@@ -455,6 +455,11 @@ CONST_OID pkixExtendedKeyUsageServerAuth[] = { PKIX_KEY_USAGE, 1 };
CONST_OID pkixExtendedKeyUsageClientAuth[] = { PKIX_KEY_USAGE, 2 };
CONST_OID pkixExtendedKeyUsageCodeSign[] = { PKIX_KEY_USAGE, 3 };
CONST_OID pkixExtendedKeyUsageEMailProtect[] = { PKIX_KEY_USAGE, 4 };
+/* IPsecEnd, IPsecTunnel, and IPsecUser are deprecated, but still in use
+ * (see RFC4945) */
+CONST_OID pkixExtendedKeyUsageIPsecEnd[] = { PKIX_KEY_USAGE, 5 };
+CONST_OID pkixExtendedKeyUsageIPsecTunnel[] = { PKIX_KEY_USAGE, 6 };
+CONST_OID pkixExtendedKeyUsageIPsecUser[] = { PKIX_KEY_USAGE, 7 };
CONST_OID pkixExtendedKeyUsageTimeStamp[] = { PKIX_KEY_USAGE, 8 };
CONST_OID pkixOCSPResponderExtendedKeyUsage[] = { PKIX_KEY_USAGE, 9 };
/* 17 replaces 5 + 6 + 7 (declared obsolete in RFC 4945) */
@@ -1778,6 +1783,18 @@ const static SECOidData oids[SEC_OID_TOTAL] = {
SEC_OID_IPSEC_IKE_INTERMEDIATE,
"IPsec IKE Intermediate",
CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(pkixExtendedKeyUsageIPsecEnd,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_END,
+ "IPsec Tunnel",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(pkixExtendedKeyUsageIPsecTunnel,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL,
+ "IPsec Tunnel",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD(pkixExtendedKeyUsageIPsecUser,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_USER,
+ "IPsec User",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
};
/* PRIVATE EXTENDED SECOID Table
diff --git a/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h
index c77aeb19f..837972e2f 100644
--- a/security/nss/lib/util/secoidt.h
+++ b/security/nss/lib/util/secoidt.h
@@ -498,6 +498,9 @@ typedef enum {
SEC_OID_EXT_KEY_USAGE_IPSEC_IKE = 358,
SEC_OID_IPSEC_IKE_END = 359,
SEC_OID_IPSEC_IKE_INTERMEDIATE = 360,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_END = 361,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL = 362,
+ SEC_OID_EXT_KEY_USAGE_IPSEC_USER = 363,
SEC_OID_TOTAL
} SECOidTag;
diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h
index f1665a2f5..c682f5d11 100644
--- a/security/nss/lib/util/secport.h
+++ b/security/nss/lib/util/secport.h
@@ -121,6 +121,11 @@ extern char *PORT_ArenaStrdup(PLArenaPool *arena, const char *str);
SEC_END_PROTOS
#define PORT_Assert PR_ASSERT
+/* This is a variation of PORT_Assert where the arguments will be always
+ * used either in Debug or not. But, in optimized mode the result will be
+ * ignored. See more details in Bug 1588015. */
+#define PORT_AssertArg PR_ASSERT_ARG
+
/* This runs a function that should return SECSuccess.
* Intended for NSS internal use only.
* The return value is asserted in a debug build, otherwise it is ignored.
diff --git a/security/nss/lib/util/utilmod.c b/security/nss/lib/util/utilmod.c
index 7d3fcda81..3ed7b3dd6 100644
--- a/security/nss/lib/util/utilmod.c
+++ b/security/nss/lib/util/utilmod.c
@@ -413,7 +413,10 @@ nssutil_ReadSecmodDB(const char *appName,
/* remove the ending newline */
len = PORT_Strlen(line);
- if (len && line[len - 1] == '\n') {
+ if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
+ len = len - 2;
+ line[len] = 0;
+ } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
len--;
line[len] = 0;
}